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