Home | History | Annotate | Download | only in testing
      1 /*
      2  * Copyright (C) 2012 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.testing;
     18 
     19 import static com.google.common.base.Preconditions.checkArgument;
     20 
     21 import com.google.common.annotations.Beta;
     22 import com.google.common.base.CharMatcher;
     23 import com.google.common.base.Charsets;
     24 import com.google.common.base.Defaults;
     25 import com.google.common.base.Equivalence;
     26 import com.google.common.base.Joiner;
     27 import com.google.common.base.Optional;
     28 import com.google.common.base.Predicate;
     29 import com.google.common.base.Predicates;
     30 import com.google.common.base.Splitter;
     31 import com.google.common.base.Stopwatch;
     32 import com.google.common.base.Ticker;
     33 import com.google.common.collect.BiMap;
     34 import com.google.common.collect.ClassToInstanceMap;
     35 import com.google.common.collect.ImmutableBiMap;
     36 import com.google.common.collect.ImmutableClassToInstanceMap;
     37 import com.google.common.collect.ImmutableCollection;
     38 import com.google.common.collect.ImmutableList;
     39 import com.google.common.collect.ImmutableListMultimap;
     40 import com.google.common.collect.ImmutableMap;
     41 import com.google.common.collect.ImmutableMultimap;
     42 import com.google.common.collect.ImmutableMultiset;
     43 import com.google.common.collect.ImmutableSet;
     44 import com.google.common.collect.ImmutableSetMultimap;
     45 import com.google.common.collect.ImmutableSortedMap;
     46 import com.google.common.collect.ImmutableSortedMultiset;
     47 import com.google.common.collect.ImmutableSortedSet;
     48 import com.google.common.collect.ImmutableTable;
     49 import com.google.common.collect.Iterators;
     50 import com.google.common.collect.ListMultimap;
     51 import com.google.common.collect.MapConstraint;
     52 import com.google.common.collect.MapConstraints;
     53 import com.google.common.collect.MapDifference;
     54 import com.google.common.collect.Maps;
     55 import com.google.common.collect.Multimap;
     56 import com.google.common.collect.Multimaps;
     57 import com.google.common.collect.Multiset;
     58 import com.google.common.collect.Ordering;
     59 import com.google.common.collect.PeekingIterator;
     60 import com.google.common.collect.Range;
     61 import com.google.common.collect.RowSortedTable;
     62 import com.google.common.collect.SetMultimap;
     63 import com.google.common.collect.Sets;
     64 import com.google.common.collect.SortedMapDifference;
     65 import com.google.common.collect.SortedMultiset;
     66 import com.google.common.collect.SortedSetMultimap;
     67 import com.google.common.collect.Table;
     68 import com.google.common.collect.Tables;
     69 import com.google.common.collect.TreeBasedTable;
     70 import com.google.common.collect.TreeMultimap;
     71 import com.google.common.io.ByteSink;
     72 import com.google.common.io.ByteSource;
     73 import com.google.common.io.ByteStreams;
     74 import com.google.common.io.CharSink;
     75 import com.google.common.io.CharSource;
     76 import com.google.common.primitives.Primitives;
     77 import com.google.common.primitives.UnsignedInteger;
     78 import com.google.common.primitives.UnsignedLong;
     79 
     80 import java.io.ByteArrayInputStream;
     81 import java.io.ByteArrayOutputStream;
     82 import java.io.File;
     83 import java.io.InputStream;
     84 import java.io.OutputStream;
     85 import java.io.PrintStream;
     86 import java.io.PrintWriter;
     87 import java.io.Reader;
     88 import java.io.Serializable;
     89 import java.io.StringReader;
     90 import java.io.StringWriter;
     91 import java.io.Writer;
     92 import java.lang.reflect.AnnotatedElement;
     93 import java.lang.reflect.Array;
     94 import java.lang.reflect.Constructor;
     95 import java.lang.reflect.Field;
     96 import java.lang.reflect.GenericDeclaration;
     97 import java.lang.reflect.InvocationTargetException;
     98 import java.lang.reflect.Modifier;
     99 import java.lang.reflect.Type;
    100 import java.math.BigDecimal;
    101 import java.math.BigInteger;
    102 import java.nio.Buffer;
    103 import java.nio.ByteBuffer;
    104 import java.nio.CharBuffer;
    105 import java.nio.DoubleBuffer;
    106 import java.nio.FloatBuffer;
    107 import java.nio.IntBuffer;
    108 import java.nio.LongBuffer;
    109 import java.nio.ShortBuffer;
    110 import java.nio.charset.Charset;
    111 import java.util.ArrayDeque;
    112 import java.util.Arrays;
    113 import java.util.Collection;
    114 import java.util.Comparator;
    115 import java.util.Currency;
    116 import java.util.Deque;
    117 import java.util.Iterator;
    118 import java.util.List;
    119 import java.util.ListIterator;
    120 import java.util.Locale;
    121 import java.util.Map;
    122 import java.util.NavigableMap;
    123 import java.util.NavigableSet;
    124 import java.util.Queue;
    125 import java.util.Random;
    126 import java.util.Set;
    127 import java.util.SortedMap;
    128 import java.util.SortedSet;
    129 import java.util.concurrent.BlockingDeque;
    130 import java.util.concurrent.BlockingQueue;
    131 import java.util.concurrent.ConcurrentHashMap;
    132 import java.util.concurrent.ConcurrentMap;
    133 import java.util.concurrent.ConcurrentNavigableMap;
    134 import java.util.concurrent.ConcurrentSkipListMap;
    135 import java.util.concurrent.CountDownLatch;
    136 import java.util.concurrent.Executor;
    137 import java.util.concurrent.LinkedBlockingDeque;
    138 import java.util.concurrent.ScheduledThreadPoolExecutor;
    139 import java.util.concurrent.ThreadFactory;
    140 import java.util.concurrent.ThreadPoolExecutor;
    141 import java.util.concurrent.TimeUnit;
    142 import java.util.logging.Level;
    143 import java.util.logging.Logger;
    144 import java.util.regex.MatchResult;
    145 import java.util.regex.Matcher;
    146 import java.util.regex.Pattern;
    147 
    148 import javax.annotation.Nullable;
    149 
    150 /**
    151  * Supplies an arbitrary "default" instance for a wide range of types, often useful in testing
    152  * utilities.
    153  *
    154  * <p>Covers arrays, enums and common types defined in {@code java.lang}, {@code java.lang.reflect},
    155  * {@code java.io}, {@code java.nio}, {@code java.math}, {@code java.util}, {@code
    156  * java.util.concurrent}, {@code java.util.regex}, {@code com.google.common.base}, {@code
    157  * com.google.common.collect} and {@code com.google.common.primitives}. In addition, if the type
    158  * exposes at least one public static final constant of the same type, one of the constants will be
    159  * used; or if the class exposes a public parameter-less constructor then it will be "new"d and
    160  * returned.
    161  *
    162  * <p>All default instances returned by {@link #get} are generics-safe. Clients won't get type
    163  * errors for using {@code get(Comparator.class)} as a {@code Comparator<Foo>}, for example.
    164  * Immutable empty instances are returned for collection types; {@code ""} for string;
    165  * {@code 0} for number types; reasonable default instance for other stateless types. For mutable
    166  * types, a fresh instance is created each time {@code get()} is called.
    167  *
    168  * @author Kevin Bourrillion
    169  * @author Ben Yu
    170  * @since 12.0
    171  */
    172 @Beta
    173 public final class ArbitraryInstances {
    174 
    175   private static final Ordering<Field> BY_FIELD_NAME = new Ordering<Field>() {
    176     @Override public int compare(Field left, Field right) {
    177       return left.getName().compareTo(right.getName());
    178     }
    179   };
    180 
    181   /**
    182    * Returns a new {@code MatchResult} that corresponds to a successful match. Apache Harmony (used
    183    * in Android) requires a successful match in order to generate a {@code MatchResult}:
    184    * http://goo.gl/5VQFmC
    185    */
    186   private static MatchResult newMatchResult() {
    187     Matcher matcher = Pattern.compile(".").matcher("X");
    188     matcher.find();
    189     return matcher.toMatchResult();
    190   }
    191 
    192   private static final ClassToInstanceMap<Object> DEFAULTS = ImmutableClassToInstanceMap.builder()
    193       // primitives
    194       .put(Object.class, "")
    195       .put(Number.class, 0)
    196       .put(UnsignedInteger.class, UnsignedInteger.ZERO)
    197       .put(UnsignedLong.class, UnsignedLong.ZERO)
    198       .put(BigInteger.class, BigInteger.ZERO)
    199       .put(BigDecimal.class, BigDecimal.ZERO)
    200       .put(CharSequence.class, "")
    201       .put(String.class, "")
    202       .put(Pattern.class, Pattern.compile(""))
    203       .put(MatchResult.class, newMatchResult())
    204       .put(TimeUnit.class, TimeUnit.SECONDS)
    205       .put(Charset.class, Charsets.UTF_8)
    206       .put(Currency.class, Currency.getInstance(Locale.US))
    207       .put(Locale.class, Locale.US)
    208       // common.base
    209       .put(CharMatcher.class, CharMatcher.NONE)
    210       .put(Joiner.class, Joiner.on(','))
    211       .put(Splitter.class, Splitter.on(','))
    212       .put(Optional.class, Optional.absent())
    213       .put(Predicate.class, Predicates.alwaysTrue())
    214       .put(Equivalence.class, Equivalence.equals())
    215       .put(Ticker.class, Ticker.systemTicker())
    216       .put(Stopwatch.class, Stopwatch.createUnstarted())
    217       // io types
    218       .put(InputStream.class, new ByteArrayInputStream(new byte[0]))
    219       .put(ByteArrayInputStream.class, new ByteArrayInputStream(new byte[0]))
    220       .put(Readable.class, new StringReader(""))
    221       .put(Reader.class, new StringReader(""))
    222       .put(StringReader.class, new StringReader(""))
    223       .put(Buffer.class, ByteBuffer.allocate(0))
    224       .put(CharBuffer.class, CharBuffer.allocate(0))
    225       .put(ByteBuffer.class, ByteBuffer.allocate(0))
    226       .put(ShortBuffer.class, ShortBuffer.allocate(0))
    227       .put(IntBuffer.class, IntBuffer.allocate(0))
    228       .put(LongBuffer.class, LongBuffer.allocate(0))
    229       .put(FloatBuffer.class, FloatBuffer.allocate(0))
    230       .put(DoubleBuffer.class, DoubleBuffer.allocate(0))
    231       .put(File.class, new File(""))
    232       .put(ByteSource.class, ByteSource.empty())
    233       .put(CharSource.class, CharSource.empty())
    234       .put(ByteSink.class, NullByteSink.INSTANCE)
    235       .put(CharSink.class, NullByteSink.INSTANCE.asCharSink(Charsets.UTF_8))
    236       // All collections are immutable empty. So safe for any type parameter.
    237       .put(Iterator.class, ImmutableSet.of().iterator())
    238       .put(PeekingIterator.class, Iterators.peekingIterator(Iterators.emptyIterator()))
    239       .put(ListIterator.class, ImmutableList.of().listIterator())
    240       .put(Iterable.class, ImmutableSet.of())
    241       .put(Collection.class, ImmutableList.of())
    242       .put(ImmutableCollection.class, ImmutableList.of())
    243       .put(List.class, ImmutableList.of())
    244       .put(ImmutableList.class, ImmutableList.of())
    245       .put(Set.class, ImmutableSet.of())
    246       .put(ImmutableSet.class, ImmutableSet.of())
    247       .put(SortedSet.class, ImmutableSortedSet.of())
    248       .put(ImmutableSortedSet.class, ImmutableSortedSet.of())
    249       .put(NavigableSet.class, Sets.unmodifiableNavigableSet(Sets.newTreeSet()))
    250       .put(Map.class, ImmutableMap.of())
    251       .put(ImmutableMap.class, ImmutableMap.of())
    252       .put(SortedMap.class, ImmutableSortedMap.of())
    253       .put(ImmutableSortedMap.class, ImmutableSortedMap.of())
    254       .put(NavigableMap.class, Maps.unmodifiableNavigableMap(Maps.newTreeMap()))
    255       .put(Multimap.class, ImmutableMultimap.of())
    256       .put(ImmutableMultimap.class, ImmutableMultimap.of())
    257       .put(ListMultimap.class, ImmutableListMultimap.of())
    258       .put(ImmutableListMultimap.class, ImmutableListMultimap.of())
    259       .put(SetMultimap.class, ImmutableSetMultimap.of())
    260       .put(ImmutableSetMultimap.class, ImmutableSetMultimap.of())
    261       .put(SortedSetMultimap.class, Multimaps.unmodifiableSortedSetMultimap(TreeMultimap.create()))
    262       .put(Multiset.class, ImmutableMultiset.of())
    263       .put(ImmutableMultiset.class, ImmutableMultiset.of())
    264       .put(SortedMultiset.class, ImmutableSortedMultiset.of())
    265       .put(ImmutableSortedMultiset.class, ImmutableSortedMultiset.of())
    266       .put(BiMap.class, ImmutableBiMap.of())
    267       .put(ImmutableBiMap.class, ImmutableBiMap.of())
    268       .put(Table.class, ImmutableTable.of())
    269       .put(ImmutableTable.class, ImmutableTable.of())
    270       .put(RowSortedTable.class, Tables.unmodifiableRowSortedTable(TreeBasedTable.create()))
    271       .put(ClassToInstanceMap.class, ImmutableClassToInstanceMap.builder().build())
    272       .put(ImmutableClassToInstanceMap.class, ImmutableClassToInstanceMap.builder().build())
    273       .put(Comparable.class, ByToString.INSTANCE)
    274       .put(Comparator.class, AlwaysEqual.INSTANCE)
    275       .put(Ordering.class, AlwaysEqual.INSTANCE)
    276       .put(Range.class, Range.all())
    277       .put(MapConstraint.class, MapConstraints.notNull())
    278       .put(MapDifference.class, Maps.difference(ImmutableMap.of(), ImmutableMap.of()))
    279       .put(SortedMapDifference.class,
    280           Maps.difference(ImmutableSortedMap.of(), ImmutableSortedMap.of()))
    281       // reflect
    282       .put(AnnotatedElement.class, Object.class)
    283       .put(GenericDeclaration.class, Object.class)
    284       .put(Type.class, Object.class)
    285       .build();
    286 
    287   /**
    288    * type -> implementation. Inherently mutable interfaces and abstract classes are mapped to their
    289    * default implementations and are "new"d upon get().
    290    */
    291   private static final ConcurrentMap<Class<?>, Class<?>> implementations = Maps.newConcurrentMap();
    292 
    293   private static <T> void setImplementation(Class<T> type, Class<? extends T> implementation) {
    294     checkArgument(type != implementation, "Don't register %s to itself!", type);
    295     checkArgument(!DEFAULTS.containsKey(type),
    296         "A default value was already registered for %s", type);
    297     checkArgument(implementations.put(type, implementation) == null,
    298         "Implementation for %s was already registered", type);
    299   }
    300 
    301   static {
    302     setImplementation(Appendable.class, StringBuilder.class);
    303     setImplementation(BlockingQueue.class, LinkedBlockingDeque.class);
    304     setImplementation(BlockingDeque.class, LinkedBlockingDeque.class);
    305     setImplementation(ConcurrentMap.class, ConcurrentHashMap.class);
    306     setImplementation(ConcurrentNavigableMap.class, ConcurrentSkipListMap.class);
    307     setImplementation(CountDownLatch.class, Dummies.DummyCountDownLatch.class);
    308     setImplementation(Deque.class, ArrayDeque.class);
    309     setImplementation(OutputStream.class, ByteArrayOutputStream.class);
    310     setImplementation(PrintStream.class, Dummies.InMemoryPrintStream.class);
    311     setImplementation(PrintWriter.class, Dummies.InMemoryPrintWriter.class);
    312     setImplementation(Queue.class, ArrayDeque.class);
    313     setImplementation(Random.class, Dummies.DeterministicRandom.class);
    314     setImplementation(ScheduledThreadPoolExecutor.class,
    315         Dummies.DummyScheduledThreadPoolExecutor.class);
    316     setImplementation(ThreadPoolExecutor.class, Dummies.DummyScheduledThreadPoolExecutor.class);
    317     setImplementation(Writer.class, StringWriter.class);
    318     setImplementation(Runnable.class, Dummies.DummyRunnable.class);
    319     setImplementation(ThreadFactory.class, Dummies.DummyThreadFactory.class);
    320     setImplementation(Executor.class, Dummies.DummyExecutor.class);
    321   }
    322 
    323   @SuppressWarnings("unchecked") // it's a subtype map
    324   @Nullable
    325   private static <T> Class<? extends T> getImplementation(Class<T> type) {
    326     return (Class<? extends T>) implementations.get(type);
    327   }
    328 
    329   private static final Logger logger = Logger.getLogger(ArbitraryInstances.class.getName());
    330 
    331   /**
    332    * Returns an arbitrary instance for {@code type}, or {@code null} if no arbitrary instance can
    333    * be determined.
    334    */
    335   @Nullable public static <T> T get(Class<T> type) {
    336     T defaultValue = DEFAULTS.getInstance(type);
    337     if (defaultValue != null) {
    338       return defaultValue;
    339     }
    340     Class<? extends T> implementation = getImplementation(type);
    341     if (implementation != null) {
    342       return get(implementation);
    343     }
    344     if (type.isEnum()) {
    345       T[] enumConstants = type.getEnumConstants();
    346       return (enumConstants.length == 0)
    347           ? null
    348           : enumConstants[0];
    349     }
    350     if (type.isArray()) {
    351       return createEmptyArray(type);
    352     }
    353     T jvmDefault = Defaults.defaultValue(Primitives.unwrap(type));
    354     if (jvmDefault != null) {
    355       return jvmDefault;
    356     }
    357     if (Modifier.isAbstract(type.getModifiers()) || !Modifier.isPublic(type.getModifiers())) {
    358       return arbitraryConstantInstanceOrNull(type);
    359     }
    360     final Constructor<T> constructor;
    361     try {
    362       constructor = type.getConstructor();
    363     } catch (NoSuchMethodException e) {
    364       return arbitraryConstantInstanceOrNull(type);
    365     }
    366     constructor.setAccessible(true); // accessibility check is too slow
    367     try {
    368       return constructor.newInstance();
    369     } catch (InstantiationException impossible) {
    370       throw new AssertionError(impossible);
    371     } catch (IllegalAccessException impossible) {
    372       throw new AssertionError(impossible);
    373     } catch (InvocationTargetException e) {
    374       logger.log(Level.WARNING, "Exception while invoking default constructor.", e.getCause());
    375       return arbitraryConstantInstanceOrNull(type);
    376     }
    377   }
    378 
    379   @Nullable private static <T> T arbitraryConstantInstanceOrNull(Class<T> type) {
    380     Field[] fields = type.getDeclaredFields();
    381     Arrays.sort(fields, BY_FIELD_NAME);
    382     for (Field field : fields) {
    383       if (Modifier.isPublic(field.getModifiers())
    384           && Modifier.isStatic(field.getModifiers())
    385           && Modifier.isFinal(field.getModifiers())) {
    386         if (field.getGenericType() == field.getType()
    387             && type.isAssignableFrom(field.getType())) {
    388           field.setAccessible(true);
    389           try {
    390             T constant = type.cast(field.get(null));
    391             if (constant != null) {
    392               return constant;
    393             }
    394           } catch (IllegalAccessException impossible) {
    395             throw new AssertionError(impossible);
    396           }
    397         }
    398       }
    399     }
    400     return null;
    401   }
    402 
    403   private static <T> T createEmptyArray(Class<T> arrayType) {
    404     return arrayType.cast(Array.newInstance(arrayType.getComponentType(), 0));
    405   }
    406 
    407   // Internal implementations of some classes, with public default constructor that get() needs.
    408   private static final class Dummies {
    409 
    410     public static final class InMemoryPrintStream extends PrintStream {
    411       public InMemoryPrintStream() {
    412         super(new ByteArrayOutputStream());
    413       }
    414     }
    415 
    416     public static final class InMemoryPrintWriter extends PrintWriter {
    417       public InMemoryPrintWriter() {
    418         super(new StringWriter());
    419       }
    420     }
    421 
    422     public static final class DeterministicRandom extends Random {
    423       @SuppressWarnings("unused") // invoked by reflection
    424       public DeterministicRandom() {
    425         super(0);
    426       }
    427     }
    428 
    429     public static final class DummyScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor {
    430       public DummyScheduledThreadPoolExecutor() {
    431         super(1);
    432       }
    433     }
    434 
    435     public static final class DummyCountDownLatch extends CountDownLatch {
    436       public DummyCountDownLatch() {
    437         super(0);
    438       }
    439     }
    440 
    441     public static final class DummyRunnable implements Runnable, Serializable {
    442       @Override public void run() {}
    443     }
    444 
    445     public static final class DummyThreadFactory implements ThreadFactory, Serializable {
    446       @Override public Thread newThread(Runnable r) {
    447         return new Thread(r);
    448       }
    449     }
    450 
    451     public static final class DummyExecutor implements Executor, Serializable {
    452       @Override public void execute(Runnable command) {}
    453     }
    454   }
    455 
    456   private static final class NullByteSink extends ByteSink implements Serializable {
    457     private static final NullByteSink INSTANCE = new NullByteSink();
    458 
    459     @Override public OutputStream openStream() {
    460       return ByteStreams.nullOutputStream();
    461     }
    462   }
    463 
    464   // Compare by toString() to satisfy 2 properties:
    465   // 1. compareTo(null) should throw NullPointerException
    466   // 2. the order is deterministic and easy to understand, for debugging purpose.
    467   private static final class ByToString implements Comparable<Object>, Serializable {
    468     private static final ByToString INSTANCE = new ByToString();
    469 
    470     @Override public int compareTo(Object o) {
    471       return toString().compareTo(o.toString());
    472     }
    473 
    474     @Override public String toString() {
    475       return "BY_TO_STRING";
    476     }
    477 
    478     private Object readResolve() {
    479       return INSTANCE;
    480     }
    481   }
    482 
    483   // Always equal is a valid total ordering. And it works for any Object.
    484   private static final class AlwaysEqual extends Ordering<Object> implements Serializable {
    485     private static final AlwaysEqual INSTANCE = new AlwaysEqual();
    486 
    487     @Override public int compare(Object o1, Object o2) {
    488       return 0;
    489     }
    490 
    491     @Override public String toString() {
    492       return "ALWAYS_EQUAL";
    493     }
    494 
    495     private Object readResolve() {
    496       return INSTANCE;
    497     }
    498   }
    499 
    500   private ArbitraryInstances() {}
    501 }
    502