1 /* 2 * Copyright (c) 2016 Mockito contributors 3 * This program is made available under the terms of the MIT License. 4 */ 5 package org.mockito.internal.stubbing.defaultanswers; 6 7 import org.mockito.internal.util.JavaEightUtil; 8 import org.mockito.internal.util.MockUtil; 9 import org.mockito.internal.util.Primitives; 10 import org.mockito.invocation.InvocationOnMock; 11 import org.mockito.mock.MockName; 12 import org.mockito.stubbing.Answer; 13 14 import static org.mockito.internal.util.ObjectMethodsGuru.isCompareToMethod; 15 import static org.mockito.internal.util.ObjectMethodsGuru.isToStringMethod; 16 17 import java.io.Serializable; 18 import java.util.*; 19 20 /** 21 * Default answer of every Mockito mock. 22 * <ul> 23 * <li> 24 * Returns appropriate primitive for primitive-returning methods 25 * </li> 26 * <li> 27 * Returns consistent values for primitive wrapper classes (e.g. int-returning method returns 0 <b>and</b> Integer-returning method returns 0, too) 28 * </li> 29 * <li> 30 * Returns empty collection for collection-returning methods (works for most commonly used collection types) 31 * </li> 32 * <li> 33 * Returns description of mock for toString() method 34 * </li> 35 * <li> 36 * Returns zero if references are equals otherwise non-zero for Comparable#compareTo(T other) method (see issue 184) 37 * </li> 38 * <li> 39 * Returns an {@code java.util.Optional#empty() empty Optional} for Optional. Similarly for primitive optional variants. 40 * </li> 41 * <li> 42 * Returns an {@code java.util.stream.Stream#empty() empty Stream} for Stream. Similarly for primitive stream variants. 43 * </li> 44 * <li> 45 * Returns null for everything else 46 * </li> 47 * </ul> 48 */ 49 public class ReturnsEmptyValues implements Answer<Object>, Serializable { 50 51 private static final long serialVersionUID = 1998191268711234347L; 52 53 54 /* (non-Javadoc) 55 * @see org.mockito.stubbing.Answer#answer(org.mockito.invocation.InvocationOnMock) 56 */ answer(InvocationOnMock invocation)57 public Object answer(InvocationOnMock invocation) { 58 if (isToStringMethod(invocation.getMethod())) { 59 Object mock = invocation.getMock(); 60 MockName name = MockUtil.getMockName(mock); 61 if (name.isDefault()) { 62 return "Mock for " + MockUtil.getMockSettings(mock).getTypeToMock().getSimpleName() + ", hashCode: " + mock.hashCode(); 63 } else { 64 return name.toString(); 65 } 66 } else if (isCompareToMethod(invocation.getMethod())) { 67 //see issue 184. 68 //mocks by default should return 0 if references are the same, otherwise some other value because they are not the same. Hence we return 1 (anything but 0 is good). 69 //Only for compareTo() method by the Comparable interface 70 return invocation.getMock() == invocation.getArgument(0) ? 0 : 1; 71 } 72 73 Class<?> returnType = invocation.getMethod().getReturnType(); 74 return returnValueFor(returnType); 75 } 76 returnValueFor(Class<?> type)77 Object returnValueFor(Class<?> type) { 78 if (Primitives.isPrimitiveOrWrapper(type)) { 79 return Primitives.defaultValue(type); 80 //new instances are used instead of Collections.emptyList(), etc. 81 //to avoid UnsupportedOperationException if code under test modifies returned collection 82 } else if (type == Iterable.class) { 83 return new ArrayList<Object>(0); 84 } else if (type == Collection.class) { 85 return new LinkedList<Object>(); 86 } else if (type == Set.class) { 87 return new HashSet<Object>(); 88 } else if (type == HashSet.class) { 89 return new HashSet<Object>(); 90 } else if (type == SortedSet.class) { 91 return new TreeSet<Object>(); 92 } else if (type == TreeSet.class) { 93 return new TreeSet<Object>(); 94 } else if (type == LinkedHashSet.class) { 95 return new LinkedHashSet<Object>(); 96 } else if (type == List.class) { 97 return new LinkedList<Object>(); 98 } else if (type == LinkedList.class) { 99 return new LinkedList<Object>(); 100 } else if (type == ArrayList.class) { 101 return new ArrayList<Object>(); 102 } else if (type == Map.class) { 103 return new HashMap<Object, Object>(); 104 } else if (type == HashMap.class) { 105 return new HashMap<Object, Object>(); 106 } else if (type == SortedMap.class) { 107 return new TreeMap<Object, Object>(); 108 } else if (type == TreeMap.class) { 109 return new TreeMap<Object, Object>(); 110 } else if (type == LinkedHashMap.class) { 111 return new LinkedHashMap<Object, Object>(); 112 } else if ("java.util.Optional".equals(type.getName())) { 113 return JavaEightUtil.emptyOptional(); 114 } else if ("java.util.OptionalDouble".equals(type.getName())) { 115 return JavaEightUtil.emptyOptionalDouble(); 116 } else if ("java.util.OptionalInt".equals(type.getName())) { 117 return JavaEightUtil.emptyOptionalInt(); 118 } else if ("java.util.OptionalLong".equals(type.getName())) { 119 return JavaEightUtil.emptyOptionalLong(); 120 } else if ("java.util.stream.Stream".equals(type.getName())) { 121 return JavaEightUtil.emptyStream(); 122 } else if ("java.util.stream.DoubleStream".equals(type.getName())) { 123 return JavaEightUtil.emptyDoubleStream(); 124 } else if ("java.util.stream.IntStream".equals(type.getName())) { 125 return JavaEightUtil.emptyIntStream(); 126 } else if ("java.util.stream.LongStream".equals(type.getName())) { 127 return JavaEightUtil.emptyLongStream(); 128 } 129 130 //Let's not care about the rest of collections. 131 return null; 132 } 133 } 134