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