1/*
2 * Copyright (C) 2011 The Guava Authors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.common.base;
18
19import com.google.common.annotations.GwtCompatible;
20import com.google.common.annotations.GwtIncompatible;
21import com.google.common.collect.ImmutableSet;
22import com.google.common.testing.EqualsTester;
23import com.google.common.testing.GcFinalization;
24import com.google.common.testing.NullPointerTester;
25import com.google.common.testing.SerializableTester;
26
27import junit.framework.TestCase;
28
29import java.lang.annotation.Retention;
30import java.lang.annotation.RetentionPolicy;
31import java.lang.ref.WeakReference;
32import java.lang.reflect.Field;
33import java.net.URLClassLoader;
34import java.util.HashSet;
35import java.util.Set;
36
37/**
38 * Tests for {@link Enums}.
39 *
40 * @author Steve McKay
41 */
42@GwtCompatible(emulated = true)
43public class EnumsTest extends TestCase {
44
45  private enum TestEnum {
46    CHEETO,
47    HONDA,
48    POODLE,
49  }
50
51  private enum OtherEnum {}
52
53  public void testValueOfFunction() {
54    Function<String, TestEnum> function = Enums.valueOfFunction(TestEnum.class);
55    assertEquals(TestEnum.CHEETO, function.apply("CHEETO"));
56    assertEquals(TestEnum.HONDA, function.apply("HONDA"));
57    assertEquals(TestEnum.POODLE, function.apply("POODLE"));
58  }
59
60  public void testValueOfFunction_caseSensitive() {
61    Function<String, TestEnum> function = Enums.valueOfFunction(TestEnum.class);
62    assertNull(function.apply("cHEETO"));
63    assertNull(function.apply("Honda"));
64    assertNull(function.apply("poodlE"));
65  }
66
67  public void testValueOfFunction_nullWhenNoMatchingConstant() {
68    Function<String, TestEnum> function = Enums.valueOfFunction(TestEnum.class);
69    assertNull(function.apply("WOMBAT"));
70  }
71
72  public void testValueOfFunction_equals() {
73    new EqualsTester()
74        .addEqualityGroup(
75            Enums.valueOfFunction(TestEnum.class), Enums.valueOfFunction(TestEnum.class))
76        .addEqualityGroup(Enums.valueOfFunction(OtherEnum.class))
77        .testEquals();
78  }
79
80  @GwtIncompatible("SerializableTester")
81  public void testValueOfFunction_serialization() {
82    Function<String, TestEnum> function = Enums.valueOfFunction(TestEnum.class);
83    SerializableTester.reserializeAndAssert(function);
84  }
85
86  public void testGetIfPresent() {
87    assertEquals(Optional.of(TestEnum.CHEETO), Enums.getIfPresent(TestEnum.class, "CHEETO"));
88    assertEquals(Optional.of(TestEnum.HONDA), Enums.getIfPresent(TestEnum.class, "HONDA"));
89    assertEquals(Optional.of(TestEnum.POODLE), Enums.getIfPresent(TestEnum.class, "POODLE"));
90
91    assertTrue(Enums.getIfPresent(TestEnum.class, "CHEETO").isPresent());
92    assertTrue(Enums.getIfPresent(TestEnum.class, "HONDA").isPresent());
93    assertTrue(Enums.getIfPresent(TestEnum.class, "POODLE").isPresent());
94
95    assertEquals(TestEnum.CHEETO, Enums.getIfPresent(TestEnum.class, "CHEETO").get());
96    assertEquals(TestEnum.HONDA, Enums.getIfPresent(TestEnum.class, "HONDA").get());
97    assertEquals(TestEnum.POODLE, Enums.getIfPresent(TestEnum.class, "POODLE").get());
98  }
99
100  public void testGetIfPresent_caseSensitive() {
101    assertFalse(Enums.getIfPresent(TestEnum.class, "cHEETO").isPresent());
102    assertFalse(Enums.getIfPresent(TestEnum.class, "Honda").isPresent());
103    assertFalse(Enums.getIfPresent(TestEnum.class, "poodlE").isPresent());
104  }
105
106  public void testGetIfPresent_whenNoMatchingConstant() {
107    assertEquals(Optional.absent(), Enums.getIfPresent(TestEnum.class, "WOMBAT"));
108  }
109
110  @GwtIncompatible("weak references")
111  public void testGetIfPresent_doesNotPreventClassUnloading() throws Exception {
112    WeakReference<?> shadowLoaderReference = doTestClassUnloading();
113    GcFinalization.awaitClear(shadowLoaderReference);
114  }
115
116  // Create a second ClassLoader and use it to get a second version of the TestEnum class.
117  // Run Enums.getIfPresent on that other TestEnum and then return a WeakReference containing the
118  // new ClassLoader. If Enums.getIfPresent does caching that prevents the shadow TestEnum
119  // (and therefore its ClassLoader) from being unloaded, then this WeakReference will never be
120  // cleared.
121  @GwtIncompatible("weak references")
122  private WeakReference<?> doTestClassUnloading() throws Exception {
123    URLClassLoader myLoader = (URLClassLoader) getClass().getClassLoader();
124    URLClassLoader shadowLoader = new URLClassLoader(myLoader.getURLs(), null);
125    @SuppressWarnings("unchecked")
126    Class<TestEnum> shadowTestEnum =
127        (Class<TestEnum>) Class.forName(TestEnum.class.getName(), false, shadowLoader);
128    assertNotSame(shadowTestEnum, TestEnum.class);
129    Set<TestEnum> shadowConstants = new HashSet<TestEnum>();
130    for (TestEnum constant : TestEnum.values()) {
131      Optional<TestEnum> result = Enums.getIfPresent(shadowTestEnum, constant.name());
132      assertTrue(result.isPresent());
133      shadowConstants.add(result.get());
134    }
135    assertEquals(ImmutableSet.copyOf(shadowTestEnum.getEnumConstants()), shadowConstants);
136    Optional<TestEnum> result = Enums.getIfPresent(shadowTestEnum, "blibby");
137    assertFalse(result.isPresent());
138    return new WeakReference<ClassLoader>(shadowLoader);
139  }
140
141  public void testStringConverter_convert() {
142    Converter<String, TestEnum> converter = Enums.stringConverter(TestEnum.class);
143    assertEquals(TestEnum.CHEETO, converter.convert("CHEETO"));
144    assertEquals(TestEnum.HONDA, converter.convert("HONDA"));
145    assertEquals(TestEnum.POODLE, converter.convert("POODLE"));
146    assertNull(converter.convert(null));
147    assertNull(converter.reverse().convert(null));
148  }
149
150  public void testStringConverter_convertError() {
151    Converter<String, TestEnum> converter = Enums.stringConverter(TestEnum.class);
152    try {
153      converter.convert("xxx");
154      fail();
155    } catch (IllegalArgumentException expected) {
156    }
157  }
158
159  public void testStringConverter_reverse() {
160    Converter<String, TestEnum> converter = Enums.stringConverter(TestEnum.class);
161    assertEquals("CHEETO", converter.reverse().convert(TestEnum.CHEETO));
162    assertEquals("HONDA", converter.reverse().convert(TestEnum.HONDA));
163    assertEquals("POODLE", converter.reverse().convert(TestEnum.POODLE));
164  }
165
166  @GwtIncompatible("NullPointerTester")
167  public void testStringConverter_nullPointerTester() throws Exception {
168    Converter<String, TestEnum> converter = Enums.stringConverter(TestEnum.class);
169    NullPointerTester tester = new NullPointerTester();
170    tester.testAllPublicInstanceMethods(converter);
171  }
172
173  public void testStringConverter_nullConversions() {
174    Converter<String, TestEnum> converter = Enums.stringConverter(TestEnum.class);
175    assertNull(converter.convert(null));
176    assertNull(converter.reverse().convert(null));
177  }
178
179  @GwtIncompatible("Class.getName()")
180  public void testStringConverter_toString() {
181    assertEquals(
182        "Enums.stringConverter(com.google.common.base.EnumsTest$TestEnum.class)",
183        Enums.stringConverter(TestEnum.class).toString());
184  }
185
186  public void testStringConverter_serialization() {
187    SerializableTester.reserializeAndAssert(Enums.stringConverter(TestEnum.class));
188  }
189
190  @GwtIncompatible("NullPointerTester")
191  public void testNullPointerExceptions() {
192    NullPointerTester tester = new NullPointerTester();
193    tester.testAllPublicStaticMethods(Enums.class);
194  }
195
196  @Retention(RetentionPolicy.RUNTIME)
197  private @interface ExampleAnnotation {}
198
199  private enum AnEnum {
200    @ExampleAnnotation FOO,
201    BAR
202  }
203
204  @GwtIncompatible("reflection")
205  public void testGetField() {
206    Field foo = Enums.getField(AnEnum.FOO);
207    assertEquals("FOO", foo.getName());
208    assertTrue(foo.isAnnotationPresent(ExampleAnnotation.class));
209
210    Field bar = Enums.getField(AnEnum.BAR);
211    assertEquals("BAR", bar.getName());
212    assertFalse(bar.isAnnotationPresent(ExampleAnnotation.class));
213  }
214}
215