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