1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 package org.apache.commons.lang.enums;
18 
19 import java.lang.reflect.InvocationTargetException;
20 import java.lang.reflect.Method;
21 import java.net.URL;
22 import java.net.URLClassLoader;
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Map;
28 
29 import junit.framework.AssertionFailedError;
30 import junit.framework.TestCase;
31 
32 import org.apache.commons.lang.SerializationUtils;
33 
34 /**
35  * Test cases for the {@link Enum} class.
36  *
37  * @author Apache Software Foundation
38  * @author Gary D. Gregory
39  * @version $Id: EnumTest.java 905636 2010-02-02 14:03:32Z niallp $
40  */
41 
42 public final class EnumTest extends TestCase {
43 
44     private static final String ENUMS_CLASS_NAME = "org.apache.commons.lang.enums.ColorEnum";
45 
EnumTest(String name)46     public EnumTest(String name) {
47         super(name);
48     }
49 
setUp()50     public void setUp() {
51     }
52 
testName()53     public void testName() {
54         assertEquals("Red", ColorEnum.RED.getName());
55         assertEquals("Green", ColorEnum.GREEN.getName());
56         assertEquals("Blue", ColorEnum.BLUE.getName());
57     }
58 
testCompareTo()59     public void testCompareTo() {
60         assertTrue(ColorEnum.BLUE.compareTo(ColorEnum.BLUE) == 0);
61         assertTrue(ColorEnum.RED.compareTo(ColorEnum.BLUE) > 0);
62         assertTrue(ColorEnum.BLUE.compareTo(ColorEnum.RED) < 0);
63         try {
64             ColorEnum.RED.compareTo(null);
65             fail();
66         } catch (NullPointerException ex) {}
67         try {
68             ColorEnum.RED.compareTo(new Object());
69             fail();
70         } catch (ClassCastException ex) {}
71     }
72 
73     public void testEquals() {
74         assertSame(ColorEnum.RED, ColorEnum.RED);
75         assertSame(ColorEnum.getEnum("Red"), ColorEnum.RED);
76         assertEquals(false, ColorEnum.RED.equals(null));
77         assertEquals(true, ColorEnum.RED.equals(ColorEnum.RED));
78         assertEquals(true, ColorEnum.RED.equals(ColorEnum.getEnum("Red")));
79     }
80 
81     public void testHashCode() {
82         assertEquals(ColorEnum.RED.hashCode(), ColorEnum.RED.hashCode());
83         assertEquals(7 + ColorEnum.class.hashCode() + 3 * "Red".hashCode(), ColorEnum.RED.hashCode());
84     }
85 
86     public void testToString() {
87         String toString = ColorEnum.RED.toString();
88         assertEquals("ColorEnum[Red]", toString);
89         assertSame(toString, ColorEnum.RED.toString());
90     }
91 
92     public void testIterator() {
93         Iterator it = ColorEnum.iterator();
94         assertSame(ColorEnum.RED, it.next());
95         assertSame(ColorEnum.GREEN, it.next());
96         assertSame(ColorEnum.BLUE, it.next());
97     }
98 
99     public void testList() {
100         List list = new ArrayList(ColorEnum.getEnumList());
101 
102         assertNotNull(list);
103 
104         assertEquals( list.size(),
105                         ColorEnum.getEnumMap().keySet().size());
106 
107         Iterator it = list.iterator();
108         assertSame(ColorEnum.RED, it.next());
109         assertSame(ColorEnum.GREEN, it.next());
110         assertSame(ColorEnum.BLUE, it.next());
111     }
112 
113     public void testMap() {
114         Map map = new HashMap(ColorEnum.getEnumMap());
115 
116         assertNotNull(map);
117         assertTrue(map.containsValue(ColorEnum.RED));
118         assertTrue(map.containsValue(ColorEnum.GREEN));
119         assertTrue(map.containsValue(ColorEnum.BLUE));
120         assertSame(ColorEnum.RED, map.get("Red"));
121         assertSame(ColorEnum.GREEN, map.get("Green"));
122         assertSame(ColorEnum.BLUE, map.get("Blue"));
123         assertEquals( map.keySet().size(),
124                         ColorEnum.getEnumList().size());
125     }
126 
127     public void testGet() {
128         assertSame(ColorEnum.RED, ColorEnum.getEnum("Red"));
129         assertSame(ColorEnum.GREEN, ColorEnum.getEnum("Green"));
130         assertSame(ColorEnum.BLUE, ColorEnum.getEnum("Blue"));
131         assertSame(null, ColorEnum.getEnum("Pink"));
132     }
133 
134     public void testSerialization() {
135         int hashCode = ColorEnum.RED.hashCode();
136         assertSame(ColorEnum.RED, SerializationUtils.clone(ColorEnum.RED));
137         assertEquals(hashCode, SerializationUtils.clone(ColorEnum.RED).hashCode());
138         assertSame(ColorEnum.GREEN, SerializationUtils.clone(ColorEnum.GREEN));
139         assertSame(ColorEnum.BLUE, SerializationUtils.clone(ColorEnum.BLUE));
140     }
141 
142     public void testBroken1() {
143         try {
144             Broken1Enum.RED.getName();
145             fail();
146         } catch (ExceptionInInitializerError ex) {
147             assertTrue(ex.getException() instanceof IllegalArgumentException);
148         }
149     }
150 
151     public void testBroken2() {
152         try {
153             Broken2Enum.RED.getName();
154             fail();
155         } catch (ExceptionInInitializerError ex) {
156             assertTrue(ex.getException() instanceof IllegalArgumentException);
157         }
158     }
159 
160     public void testBroken3() {
161         try {
162             Broken3Enum.RED.getName();
163             fail();
164         } catch (ExceptionInInitializerError ex) {
165             assertTrue(ex.getException() instanceof IllegalArgumentException);
166         }
167     }
168 
169     public void testBroken1Operation() {
170         try {
171             Broken1OperationEnum.PLUS.getName();
172             fail();
173         } catch (ExceptionInInitializerError ex) {
174             assertTrue(ex.getException() instanceof IllegalArgumentException);
175         }
176     }
177 
178     public void testBroken2Operation() {
179         try {
180             Broken2OperationEnum.PLUS.getName();
181             fail();
182         } catch (ExceptionInInitializerError ex) {
183             assertTrue(ex.getException() instanceof IllegalArgumentException);
184         }
185     }
186 
187     public void testBroken3Operation() {
188         try {
189             Broken3OperationEnum.PLUS.getName();
190             fail();
191         } catch (ExceptionInInitializerError ex) {
192             assertTrue(ex.getException() instanceof IllegalArgumentException);
193         }
194     }
195 
196     public void testBroken4Operation() {
197         try {
198             Broken4OperationEnum.PLUS.getName();
199             fail();
200         } catch (ExceptionInInitializerError ex) {
201             assertTrue(ex.getException() instanceof IllegalArgumentException);
202         }
203     }
204 
205     public void testBroken5Operation() {
206         try {
207             Broken5OperationEnum.PLUS.getName();
208             fail();
209         } catch (ExceptionInInitializerError ex) {
210             assertTrue(ex.getException() instanceof IllegalArgumentException);
211         }
212     }
213 
214     public void testOperationGet() {
215         assertSame(OperationEnum.PLUS, OperationEnum.getEnum("Plus"));
216         assertSame(OperationEnum.MINUS, OperationEnum.getEnum("Minus"));
217         assertSame(null, OperationEnum.getEnum("Pink"));
218     }
219 
220     public void testOperationSerialization() {
221         assertSame(OperationEnum.PLUS, SerializationUtils.clone(OperationEnum.PLUS));
222         assertSame(OperationEnum.MINUS, SerializationUtils.clone(OperationEnum.MINUS));
223     }
224 
225     public void testOperationToString() {
226         assertEquals("OperationEnum[Plus]", OperationEnum.PLUS.toString());
227     }
228 
229     public void testOperationList() {
230         List list = OperationEnum.getEnumList();
231         assertNotNull(list);
232         assertEquals(2, list.size());
233         assertEquals(list.size(), OperationEnum.getEnumMap().keySet().size());
234 
235         Iterator it = list.iterator();
236         assertSame(OperationEnum.PLUS, it.next());
237         assertSame(OperationEnum.MINUS, it.next());
238     }
239 
240     public void testOperationMap() {
241         Map map = OperationEnum.getEnumMap();
242         assertNotNull(map);
243         assertEquals(map.keySet().size(), OperationEnum.getEnumList().size());
244 
245         assertTrue(map.containsValue(OperationEnum.PLUS));
246         assertTrue(map.containsValue(OperationEnum.MINUS));
247         assertSame(OperationEnum.PLUS, map.get("Plus"));
248         assertSame(OperationEnum.MINUS, map.get("Minus"));
249     }
250 
251     public void testOperationCalculation() {
252         assertEquals(3, OperationEnum.PLUS.eval(1, 2));
253         assertEquals(-1, OperationEnum.MINUS.eval(1, 2));
254     }
255 
256     //-----------------------------------------------------------------------
257     public void testExtended1Get() {
258         assertSame(Extended1Enum.ALPHA, Extended1Enum.getEnum("Alpha"));
259         assertSame(Extended1Enum.BETA, Extended1Enum.getEnum("Beta"));
260         assertSame(null, Extended1Enum.getEnum("Gamma"));
261         assertSame(null, Extended1Enum.getEnum("Delta"));
262     }
263 
264     public void testExtended2Get() {
265         assertSame(Extended1Enum.ALPHA, Extended2Enum.ALPHA);
266         assertSame(Extended1Enum.BETA, Extended2Enum.BETA);
267 
268         assertSame(Extended2Enum.ALPHA, Extended2Enum.getEnum("Alpha"));
269         assertSame(Extended2Enum.BETA, Extended2Enum.getEnum("Beta"));
270         assertSame(Extended2Enum.GAMMA, Extended2Enum.getEnum("Gamma"));
271         assertSame(null, Extended2Enum.getEnum("Delta"));
272     }
273 
274     public void testExtended3Get() {
275         assertSame(Extended2Enum.ALPHA, Extended3Enum.ALPHA);
276         assertSame(Extended2Enum.BETA, Extended3Enum.BETA);
277         assertSame(Extended2Enum.GAMMA, Extended3Enum.GAMMA);
278 
279         assertSame(Extended3Enum.ALPHA, Extended3Enum.getEnum("Alpha"));
280         assertSame(Extended3Enum.BETA, Extended3Enum.getEnum("Beta"));
281         assertSame(Extended3Enum.GAMMA, Extended3Enum.getEnum("Gamma"));
282         assertSame(Extended3Enum.DELTA, Extended3Enum.getEnum("Delta"));
283     }
284 
285     public void testExtendedSerialization() {
286         assertSame(Extended1Enum.ALPHA, SerializationUtils.clone(Extended1Enum.ALPHA));
287         assertSame(Extended1Enum.BETA, SerializationUtils.clone(Extended1Enum.BETA));
288         assertSame(Extended2Enum.GAMMA, SerializationUtils.clone(Extended2Enum.GAMMA));
289         assertSame(Extended3Enum.DELTA, SerializationUtils.clone(Extended3Enum.DELTA));
290     }
291 
292     public void testExtendedToString() {
293         assertEquals("Extended1Enum[Alpha]", Extended1Enum.ALPHA.toString());
294         assertEquals("Extended1Enum[Beta]", Extended1Enum.BETA.toString());
295 
296         assertEquals("Extended1Enum[Alpha]", Extended2Enum.ALPHA.toString());
297         assertEquals("Extended1Enum[Beta]", Extended2Enum.BETA.toString());
298         assertEquals("Extended2Enum[Gamma]", Extended2Enum.GAMMA.toString());
299 
300         assertEquals("Extended1Enum[Alpha]", Extended3Enum.ALPHA.toString());
301         assertEquals("Extended1Enum[Beta]", Extended3Enum.BETA.toString());
302         assertEquals("Extended2Enum[Gamma]", Extended3Enum.GAMMA.toString());
303         assertEquals("Extended3Enum[Delta]", Extended3Enum.DELTA.toString());
304     }
305 
306     public void testExtended1List() {
307         List list = Extended1Enum.getEnumList();
308         assertNotNull(list);
309         assertEquals(2, list.size());
310         assertEquals(list.size(), Extended1Enum.getEnumMap().keySet().size());
311 
312         Iterator it = list.iterator();
313         assertSame(Extended1Enum.ALPHA, it.next());
314         assertSame(Extended1Enum.BETA, it.next());
315     }
316 
317     public void testExtended2List() {
318         List list = Extended2Enum.getEnumList();
319         assertNotNull(list);
320         assertEquals(3, list.size());
321         assertEquals(list.size(), Extended2Enum.getEnumMap().keySet().size());
322 
323         Iterator it = list.iterator();
324         assertSame(Extended2Enum.ALPHA, it.next());
325         assertSame(Extended2Enum.BETA, it.next());
326         assertSame(Extended2Enum.GAMMA, it.next());
327     }
328 
329     public void testExtended3List() {
330         List list = Extended3Enum.getEnumList();
331         assertNotNull(list);
332         assertEquals(4, list.size());
333         assertEquals(list.size(), Extended3Enum.getEnumMap().keySet().size());
334 
335         Iterator it = list.iterator();
336         assertSame(Extended3Enum.ALPHA, it.next());
337         assertSame(Extended3Enum.BETA, it.next());
338         assertSame(Extended3Enum.GAMMA, it.next());
339         assertSame(Extended3Enum.DELTA, it.next());
340     }
341 
342     public void testExtended1Map() {
343         Map map = Extended1Enum.getEnumMap();
344         assertNotNull(map);
345         assertEquals(map.keySet().size(), Extended1Enum.getEnumList().size());
346 
347         assertTrue(map.containsValue(Extended1Enum.ALPHA));
348         assertTrue(map.containsValue(Extended1Enum.BETA));
349         assertSame(Extended1Enum.ALPHA, map.get("Alpha"));
350         assertSame(Extended1Enum.BETA, map.get("Beta"));
351     }
352 
353     public void testExtended2Map() {
354         Map map = Extended2Enum.getEnumMap();
355         assertNotNull(map);
356         assertEquals(map.keySet().size(), Extended2Enum.getEnumList().size());
357 
358         assertTrue(map.containsValue(Extended2Enum.ALPHA));
359         assertTrue(map.containsValue(Extended2Enum.BETA));
360         assertTrue(map.containsValue(Extended2Enum.GAMMA));
361         assertSame(Extended2Enum.ALPHA, map.get("Alpha"));
362         assertSame(Extended2Enum.BETA, map.get("Beta"));
363         assertSame(Extended2Enum.GAMMA, map.get("Gamma"));
364     }
365 
366     public void testExtended3Map() {
367         Map map = Extended3Enum.getEnumMap();
368         assertNotNull(map);
369         assertEquals(map.keySet().size(), Extended3Enum.getEnumList().size());
370 
371         assertTrue(map.containsValue(Extended3Enum.ALPHA));
372         assertTrue(map.containsValue(Extended3Enum.BETA));
373         assertTrue(map.containsValue(Extended3Enum.GAMMA));
374         assertTrue(map.containsValue(Extended3Enum.DELTA));
375         assertSame(Extended3Enum.ALPHA, map.get("Alpha"));
376         assertSame(Extended3Enum.BETA, map.get("Beta"));
377         assertSame(Extended3Enum.GAMMA, map.get("Gamma"));
378         assertSame(Extended3Enum.DELTA, map.get("Delta"));
379     }
380 
381     //-----------------------------------------------------------------------
382     public void testNested() {
383         List list = new ArrayList(Nest.ColorEnum.getEnumList());
384         assertEquals(3, list.size());  // all is well
385         Iterator it = list.iterator();
386         assertSame(Nest.ColorEnum.RED, it.next());
387         assertSame(Nest.ColorEnum.GREEN, it.next());
388         assertSame(Nest.ColorEnum.BLUE, it.next());
389         // This nesting works because the enum constants are defined in the SAME
390         // class as the getEnumList(). It just acts as a normal enum.
391     }
392 
393     public void testNestedBroken() {
394         List list = new ArrayList(NestBroken.ColorEnum.getEnumList());
395         try {
396             assertEquals(0, list.size());  // no enums!!!
397             // this is BROKEN because the enum constants are defined in a DIFFERENT
398             // class from getEnumList(). Once NestBroken class is referenced,
399             // and thus class loaded with its enum constants, the getEnumList works:
400         } catch (AssertionFailedError ex) {
401             // this actually works and isn't broken on Linux SunJDK1.4.1, so...
402             assertEquals(3, list.size());
403         }
404         new NestBroken();
405         list = new ArrayList(NestBroken.ColorEnum.getEnumList());
406         assertEquals(3, list.size());  // all is well!!!
407         Iterator it = list.iterator();
408         assertSame(NestBroken.RED, it.next());
409         assertSame(NestBroken.GREEN, it.next());
410         assertSame(NestBroken.BLUE, it.next());
411     }
412 
413     public void testNestedLinked() {
414         List list = new ArrayList(NestLinked.ColorEnum.getEnumList());
415         assertEquals(3, list.size());  // all is well
416         Iterator it = list.iterator();
417         assertSame(NestLinked.RED, it.next());
418         assertSame(NestLinked.GREEN, it.next());
419         assertSame(NestLinked.BLUE, it.next());
420         // This nesting works because a static block in the enum class forces a
421         // class load of the outer class which defines the enum constants.
422     }
423 
424     public void testNestedReferenced() {
425         List list = new ArrayList(NestReferenced.ColorEnum.getEnumList());
426         assertEquals(3, list.size());  // all is well
427         Iterator it = list.iterator();
428         assertSame(NestReferenced.RED, it.next());
429         assertSame(NestReferenced.GREEN, it.next());
430         assertSame(NestReferenced.BLUE, it.next());
431         // This nesting works because the enum constants are actually defined in
432         // the SAME class as the getEnumList(). The references in the outer class
433         // are just extra references.
434     }
435 
436     public void testColorEnumEqualsWithDifferentClassLoaders() throws SecurityException, IllegalArgumentException,
437             ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
438         this.testWithDifferentClassLoaders(ColorEnum.BLUE);
439         this.testWithDifferentClassLoaders(ColorEnum.GREEN);
440         this.testWithDifferentClassLoaders(ColorEnum.RED);
441     }
442 
443     void testWithDifferentClassLoaders(ColorEnum colorEnum) throws ClassNotFoundException, SecurityException,
444             NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
445         // Sanity checks:
446         assertTrue(colorEnum.equals(colorEnum));
447         assertNotNull(ColorEnum.class.getClassLoader());
448         // set up:
449         ClassLoader myClassLoader = EnumTest.class.getClassLoader();
450         if (!(myClassLoader instanceof URLClassLoader)) {
451             fail("EnumTest ClassLoader = " + (myClassLoader == null ? null : myClassLoader.getClass().getName()));
452         }
453         ClassLoader classLoader = URLClassLoader.newInstance( ((URLClassLoader)myClassLoader).getURLs(), null);
454         Object enumObjectFromOtherClassLoader = this.getColorEnum(classLoader, colorEnum.getName());
455 
456         // the real test, part 1.
457         try {
458             ColorEnum testCase = (ColorEnum) enumObjectFromOtherClassLoader;
459             fail("Should have thrown a ClassCastException for " + testCase);
460         } catch (ClassCastException e) {
461             // normal.
462         }
463 
464         // the real test, part 2.
465         assertEquals("The two objects should match even though they are from different class loaders", colorEnum,
466                 enumObjectFromOtherClassLoader);
467 
468         // the real test, part 3 - testing equals(Object)
469         int falseCount = 0;
470         for (Iterator iter = ColorEnum.iterator(); iter.hasNext();) {
471             ColorEnum element = (ColorEnum) iter.next();
472             if (!colorEnum.equals(element)) {
473                 falseCount++;
474                 assertFalse(enumObjectFromOtherClassLoader.equals(element));
475             }
476         }
477         assertEquals(ColorEnum.getEnumList().size() - 1, falseCount);
478 
479         // the real test, part 4 - testing compareTo(Object) == 0
480         falseCount = 0;
481         for (Iterator iter = ColorEnum.iterator(); iter.hasNext();) {
482             ColorEnum element = (ColorEnum) iter.next();
483             if (!colorEnum.equals(element)) {
484                 falseCount++;
485                 assertFalse( ((Comparable)enumObjectFromOtherClassLoader).compareTo(element) == 0);
486             }
487         }
488         assertEquals(ColorEnum.getEnumList().size() - 1, falseCount);
489     }
490 
491     Object getColorEnum(ClassLoader classLoader, String color) throws ClassNotFoundException, SecurityException,
492             NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
493         // Sanity check:
494         ColorEnum.RED.equals(ColorEnum.RED);
495         assertNotNull(ColorEnum.class.getClassLoader());
496         // set up:
497         assertNotNull(classLoader);
498         assertFalse(classLoader.equals(ColorEnum.class.getClassLoader()));
499         Class otherColorEnumClass = null;
500         try {
501             otherColorEnumClass = classLoader.loadClass(ENUMS_CLASS_NAME);
502         } catch (ClassNotFoundException e) {
503             // Dump some information to help debug class loader issues under different JREs, Ant, Eclipse.
504             System.err.println("Could not load " + ENUMS_CLASS_NAME + " from the class loader " + classLoader);
505             URLClassLoader urlCl = (URLClassLoader) classLoader;
506             URL[] urls = urlCl.getURLs();
507             System.err.println("Class loader has " + urls.length + " URLs:");
508             for (int i = 0; i < urls.length; i++) {
509                 System.err.println("URL[" + i + "] = " + urls[i]);
510             }
511             e.printStackTrace();
512             throw e;
513         }
514         assertNotNull(otherColorEnumClass);
515         assertNotNull(otherColorEnumClass.getClassLoader());
516         assertTrue(classLoader.equals(otherColorEnumClass.getClassLoader()));
517         assertFalse(otherColorEnumClass.getClassLoader().equals(ColorEnum.class.getClassLoader()));
518         Method method = otherColorEnumClass.getMethod("getEnum", new Class[]{String.class});
519         Object enumObject = method.invoke(otherColorEnumClass, new Object[]{color});
520         assertNotNull(enumObject);
521         assertFalse(ColorEnum.class.equals(enumObject.getClass()));
522         assertFalse(ColorEnum.class == enumObject.getClass());
523         return enumObject;
524     }
525 
526     public void testEqualsToWrongInstance() {
527         for (Iterator iter = ColorEnum.iterator(); iter.hasNext();) {
528             ColorEnum element = (ColorEnum) iter.next();
529             this.testEqualsToWrongInstance(element);
530         }
531     }
532 
533     void testEqualsToWrongInstance(ColorEnum colorEnum) {
534         assertEquals(false, colorEnum.equals("test"));
535         assertEquals(false, colorEnum.equals(new Integer(1)));
536         assertEquals(false, colorEnum.equals(new Boolean(true)));
537         assertEquals(false, colorEnum.equals(new StringBuffer("test")));
538         assertEquals(false, colorEnum.equals(new Object()));
539         assertEquals(false, colorEnum.equals(null));
540         assertEquals(false, colorEnum.equals(""));
541         assertEquals(false, colorEnum.equals(ColorEnum.getEnum(null)));
542         assertEquals(false, colorEnum.equals(ColorEnum.getEnum("")));
543         assertEquals(false, colorEnum.equals(ColorEnum.getEnum("This ColorEnum does not exist.")));
544     }
545 }
546