1/*
2 * Copyright (c) 2007 Mockito contributors
3 * This program is made available under the terms of the MIT License.
4 */
5package org.mockito.internal.creation;
6
7import org.mockito.MockSettings;
8import org.mockito.exceptions.Reporter;
9import org.mockito.internal.creation.settings.CreationSettings;
10import org.mockito.internal.debugging.VerboseMockInvocationLogger;
11import org.mockito.internal.util.MockCreationValidator;
12import org.mockito.internal.util.MockNameImpl;
13import org.mockito.internal.util.MockitoMock;
14import org.mockito.internal.util.MockitoSpy;
15import org.mockito.listeners.InvocationListener;
16import org.mockito.mock.MockCreationSettings;
17import org.mockito.mock.MockName;
18import org.mockito.stubbing.Answer;
19
20import java.io.Serializable;
21import java.util.HashSet;
22import java.util.List;
23import java.util.Set;
24
25import static org.mockito.internal.util.collections.Sets.newSet;
26
27@SuppressWarnings("unchecked")
28public class MockSettingsImpl<T> extends CreationSettings<T> implements MockSettings, MockCreationSettings<T> {
29
30    private static final long serialVersionUID = 4475297236197939569L;
31
32    public MockSettings serializable() {
33        this.serializable = true;
34        return this;
35    }
36
37    public MockSettings extraInterfaces(Class... extraInterfaces) {
38        if (extraInterfaces == null || extraInterfaces.length == 0) {
39            new Reporter().extraInterfacesRequiresAtLeastOneInterface();
40        }
41
42        for (Class i : extraInterfaces) {
43            if (i == null) {
44                new Reporter().extraInterfacesDoesNotAcceptNullParameters();
45            } else if (!i.isInterface()) {
46                new Reporter().extraInterfacesAcceptsOnlyInterfaces(i);
47            }
48        }
49        this.extraInterfaces = newSet(extraInterfaces);
50        return this;
51    }
52
53    public MockName getMockName() {
54        return mockName;
55    }
56
57    public Set<Class> getExtraInterfaces() {
58        return extraInterfaces;
59    }
60
61    public Object getSpiedInstance() {
62        return spiedInstance;
63    }
64
65    public MockSettings name(String name) {
66        this.name = name;
67        return this;
68    }
69
70    public MockSettings spiedInstance(Object spiedInstance) {
71        this.spiedInstance = spiedInstance;
72        return this;
73    }
74
75    public MockSettings defaultAnswer(Answer defaultAnswer) {
76        this.defaultAnswer = defaultAnswer;
77        if (defaultAnswer == null) {
78            new Reporter().defaultAnswerDoesNotAcceptNullParameter();
79        }
80        return this;
81    }
82
83    public Answer<Object> getDefaultAnswer() {
84        return defaultAnswer;
85    }
86
87    public boolean isSerializable() {
88        return serializable;
89    }
90
91    public MockSettingsImpl stubOnly() {
92        this.stubOnly = true;
93        return this;
94    }
95
96    public boolean isStubOnly() {
97        return this.stubOnly;
98    }
99
100    public MockSettings verboseLogging() {
101        if (!invocationListenersContainsType(VerboseMockInvocationLogger.class)) {
102            invocationListeners(new VerboseMockInvocationLogger());
103        }
104        return this;
105    }
106
107    public MockSettings invocationListeners(InvocationListener... listeners) {
108        if (listeners == null || listeners.length == 0) {
109            new Reporter().invocationListenersRequiresAtLeastOneListener();
110        }
111        for (InvocationListener listener : listeners) {
112            if (listener == null) {
113                new Reporter().invocationListenerDoesNotAcceptNullParameters();
114            }
115            this.invocationListeners.add(listener);
116        }
117        return this;
118    }
119
120    private boolean invocationListenersContainsType(Class<?> clazz) {
121        for (InvocationListener listener : invocationListeners) {
122            if (listener.getClass().equals(clazz)) {
123                return true;
124            }
125        }
126        return false;
127    }
128
129    public List<InvocationListener> getInvocationListeners() {
130        return this.invocationListeners;
131    }
132
133    public boolean hasInvocationListeners() {
134        return !invocationListeners.isEmpty();
135    }
136
137    public Class<T> getTypeToMock() {
138        return typeToMock;
139    }
140
141    public MockCreationSettings<T> confirm(Class<T> typeToMock) {
142        return validatedSettings(typeToMock, this);
143    }
144
145    private static <T> CreationSettings<T> validatedSettings(Class<T> typeToMock, CreationSettings<T> source) {
146        MockCreationValidator validator = new MockCreationValidator();
147
148        validator.validateType(typeToMock);
149        validator.validateExtraInterfaces(typeToMock, source.getExtraInterfaces());
150        validator.validateMockedType(typeToMock, source.getSpiedInstance());
151
152        //TODO SF - add this validation and also add missing coverage
153//        validator.validateDelegatedInstance(classToMock, settings.getDelegatedInstance());
154
155        validator.validateSerializable(typeToMock, source.isSerializable());
156
157        CreationSettings<T> settings = new CreationSettings<T>(source);
158        settings.setMockName(new MockNameImpl(source.getName(), typeToMock));
159        settings.setTypeToMock(typeToMock);
160        settings.setExtraInterfaces(prepareExtraInterfaces(source));
161        return settings;
162    }
163
164    private static Set<Class> prepareExtraInterfaces(CreationSettings settings) {
165        Set<Class> interfaces = new HashSet<Class>(settings.getExtraInterfaces());
166        interfaces.add(MockitoMock.class);
167        if(settings.isSerializable()) {
168            interfaces.add(Serializable.class);
169        }
170        if (settings.getSpiedInstance() != null) {
171            interfaces.add(MockitoSpy.class);
172        }
173        return interfaces;
174    }
175
176}
177
178