• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.google.common.base;
18 
19 import static com.google.common.base.StandardSystemProperty.JAVA_CLASS_PATH;
20 import static com.google.common.base.StandardSystemProperty.PATH_SEPARATOR;
21 import static com.google.common.truth.Truth.assertThat;
22 import static org.junit.Assert.assertThrows;
23 
24 import com.google.common.annotations.GwtIncompatible;
25 import com.google.common.annotations.J2ktIncompatible;
26 import com.google.common.collect.ImmutableList;
27 import com.google.common.collect.ImmutableSet;
28 import com.google.common.testing.GcFinalization;
29 import com.google.common.testing.NullPointerTester;
30 import com.google.common.testing.SerializableTester;
31 import java.io.File;
32 import java.lang.annotation.Retention;
33 import java.lang.annotation.RetentionPolicy;
34 import java.lang.ref.WeakReference;
35 import java.lang.reflect.Field;
36 import java.net.MalformedURLException;
37 import java.net.URL;
38 import java.net.URLClassLoader;
39 import java.util.HashSet;
40 import java.util.Set;
41 import junit.framework.TestCase;
42 
43 /**
44  * Tests for {@link Enums}.
45  *
46  * @author Steve McKay
47  */
48 @GwtIncompatible
49 @J2ktIncompatible
50 public class EnumsTest extends TestCase {
51 
52   private enum TestEnum {
53     CHEETO,
54     HONDA,
55     POODLE,
56   }
57 
58   private enum OtherEnum {}
59 
testGetIfPresent()60   public void testGetIfPresent() {
61     assertThat(Enums.getIfPresent(TestEnum.class, "CHEETO")).hasValue(TestEnum.CHEETO);
62     assertThat(Enums.getIfPresent(TestEnum.class, "HONDA")).hasValue(TestEnum.HONDA);
63     assertThat(Enums.getIfPresent(TestEnum.class, "POODLE")).hasValue(TestEnum.POODLE);
64 
65     assertThat(Enums.getIfPresent(TestEnum.class, "CHEETO")).isPresent();
66     assertThat(Enums.getIfPresent(TestEnum.class, "HONDA")).isPresent();
67     assertThat(Enums.getIfPresent(TestEnum.class, "POODLE")).isPresent();
68 
69     assertThat(Enums.getIfPresent(TestEnum.class, "CHEETO")).hasValue(TestEnum.CHEETO);
70     assertThat(Enums.getIfPresent(TestEnum.class, "HONDA")).hasValue(TestEnum.HONDA);
71     assertThat(Enums.getIfPresent(TestEnum.class, "POODLE")).hasValue(TestEnum.POODLE);
72   }
73 
testGetIfPresent_caseSensitive()74   public void testGetIfPresent_caseSensitive() {
75     assertThat(Enums.getIfPresent(TestEnum.class, "cHEETO")).isAbsent();
76     assertThat(Enums.getIfPresent(TestEnum.class, "Honda")).isAbsent();
77     assertThat(Enums.getIfPresent(TestEnum.class, "poodlE")).isAbsent();
78   }
79 
testGetIfPresent_whenNoMatchingConstant()80   public void testGetIfPresent_whenNoMatchingConstant() {
81     assertThat(Enums.getIfPresent(TestEnum.class, "WOMBAT")).isAbsent();
82   }
83 
84 
85   @J2ktIncompatible
86   @GwtIncompatible // weak references
87   @AndroidIncompatible // depends on details of GC and classloading
testGetIfPresent_doesNotPreventClassUnloading()88   public void testGetIfPresent_doesNotPreventClassUnloading() throws Exception {
89     WeakReference<?> shadowLoaderReference = doTestClassUnloading();
90     GcFinalization.awaitClear(shadowLoaderReference);
91   }
92 
93   // Create a second ClassLoader and use it to get a second version of the TestEnum class.
94   // Run Enums.getIfPresent on that other TestEnum and then return a WeakReference containing the
95   // new ClassLoader. If Enums.getIfPresent does caching that prevents the shadow TestEnum
96   // (and therefore its ClassLoader) from being unloaded, then this WeakReference will never be
97   // cleared.
98   @J2ktIncompatible
99   @GwtIncompatible // weak references
doTestClassUnloading()100   private WeakReference<?> doTestClassUnloading() throws Exception {
101     URLClassLoader shadowLoader = new URLClassLoader(getClassPathUrls(), null);
102     @SuppressWarnings("unchecked")
103     Class<TestEnum> shadowTestEnum =
104         (Class<TestEnum>) Class.forName(TestEnum.class.getName(), false, shadowLoader);
105     assertNotSame(shadowTestEnum, TestEnum.class);
106     // We can't write Set<TestEnum> because that is a Set of the TestEnum from the original
107     // ClassLoader.
108     Set<Object> shadowConstants = new HashSet<>();
109     for (TestEnum constant : TestEnum.values()) {
110       Optional<TestEnum> result = Enums.getIfPresent(shadowTestEnum, constant.name());
111       assertThat(result).isPresent();
112       shadowConstants.add(result.get());
113     }
114     assertEquals(ImmutableSet.<Object>copyOf(shadowTestEnum.getEnumConstants()), shadowConstants);
115     Optional<TestEnum> result = Enums.getIfPresent(shadowTestEnum, "blibby");
116     assertThat(result).isAbsent();
117     return new WeakReference<>(shadowLoader);
118   }
119 
120   @GwtIncompatible // stringConverter
testStringConverter_convert()121   public void testStringConverter_convert() {
122     Converter<String, TestEnum> converter = Enums.stringConverter(TestEnum.class);
123     assertEquals(TestEnum.CHEETO, converter.convert("CHEETO"));
124     assertEquals(TestEnum.HONDA, converter.convert("HONDA"));
125     assertEquals(TestEnum.POODLE, converter.convert("POODLE"));
126     assertNull(converter.convert(null));
127     assertNull(converter.reverse().convert(null));
128   }
129 
130   @GwtIncompatible // stringConverter
testStringConverter_convertError()131   public void testStringConverter_convertError() {
132     Converter<String, TestEnum> converter = Enums.stringConverter(TestEnum.class);
133     assertThrows(IllegalArgumentException.class, () -> converter.convert("xxx"));
134   }
135 
136   @GwtIncompatible // stringConverter
testStringConverter_reverse()137   public void testStringConverter_reverse() {
138     Converter<String, TestEnum> converter = Enums.stringConverter(TestEnum.class);
139     assertEquals("CHEETO", converter.reverse().convert(TestEnum.CHEETO));
140     assertEquals("HONDA", converter.reverse().convert(TestEnum.HONDA));
141     assertEquals("POODLE", converter.reverse().convert(TestEnum.POODLE));
142   }
143 
144   @J2ktIncompatible
145   @GwtIncompatible // stringConverter
testStringConverter_nullPointerTester()146   public void testStringConverter_nullPointerTester() throws Exception {
147     Converter<String, TestEnum> converter = Enums.stringConverter(TestEnum.class);
148     NullPointerTester tester = new NullPointerTester();
149     tester.testAllPublicInstanceMethods(converter);
150   }
151 
152   @GwtIncompatible // stringConverter
testStringConverter_nullConversions()153   public void testStringConverter_nullConversions() {
154     Converter<String, TestEnum> converter = Enums.stringConverter(TestEnum.class);
155     assertNull(converter.convert(null));
156     assertNull(converter.reverse().convert(null));
157   }
158 
159   @J2ktIncompatible
160   @GwtIncompatible // Class.getName()
testStringConverter_toString()161   public void testStringConverter_toString() {
162     assertEquals(
163         "Enums.stringConverter(com.google.common.base.EnumsTest$TestEnum.class)",
164         Enums.stringConverter(TestEnum.class).toString());
165   }
166 
167   @GwtIncompatible // stringConverter
testStringConverter_serialization()168   public void testStringConverter_serialization() {
169     SerializableTester.reserializeAndAssert(Enums.stringConverter(TestEnum.class));
170   }
171 
172   @J2ktIncompatible
173   @GwtIncompatible // NullPointerTester
testNullPointerExceptions()174   public void testNullPointerExceptions() {
175     NullPointerTester tester = new NullPointerTester();
176     tester.testAllPublicStaticMethods(Enums.class);
177   }
178 
179   @Retention(RetentionPolicy.RUNTIME)
180   private @interface ExampleAnnotation {}
181 
182   private enum AnEnum {
183     @ExampleAnnotation
184     FOO,
185     BAR
186   }
187 
188   @J2ktIncompatible
189   @GwtIncompatible // reflection
testGetField()190   public void testGetField() {
191     Field foo = Enums.getField(AnEnum.FOO);
192     assertEquals("FOO", foo.getName());
193     assertTrue(foo.isAnnotationPresent(ExampleAnnotation.class));
194 
195     Field bar = Enums.getField(AnEnum.BAR);
196     assertEquals("BAR", bar.getName());
197     assertFalse(bar.isAnnotationPresent(ExampleAnnotation.class));
198   }
199 
200   @J2ktIncompatible
201   @GwtIncompatible // Class.getClassLoader()
getClassPathUrls()202   private URL[] getClassPathUrls() {
203     ClassLoader classLoader = getClass().getClassLoader();
204     return classLoader instanceof URLClassLoader
205         ? ((URLClassLoader) classLoader).getURLs()
206         : parseJavaClassPath().toArray(new URL[0]);
207   }
208 
209   /**
210    * Returns the URLs in the class path specified by the {@code java.class.path} {@linkplain
211    * System#getProperty system property}.
212    */
213   // TODO(b/65488446): Make this a public API.
214   @J2ktIncompatible
215   @GwtIncompatible
parseJavaClassPath()216   private static ImmutableList<URL> parseJavaClassPath() {
217     ImmutableList.Builder<URL> urls = ImmutableList.builder();
218     for (String entry : Splitter.on(PATH_SEPARATOR.value()).split(JAVA_CLASS_PATH.value())) {
219       try {
220         try {
221           urls.add(new File(entry).toURI().toURL());
222         } catch (SecurityException e) { // File.toURI checks to see if the file is a directory
223           urls.add(new URL("file", null, new File(entry).getAbsolutePath()));
224         }
225       } catch (MalformedURLException e) {
226         AssertionError error = new AssertionError("malformed class path entry: " + entry);
227         error.initCause(e);
228         throw error;
229       }
230     }
231     return urls.build();
232   }
233 }
234