1 /*
2 * MIT License
3 * Copyright (c) 2006-2025 JMockit developers
4 * See LICENSE file for full license text.
5 */
6 package mockit;
7
8 import edu.umd.cs.findbugs.annotations.NonNull;
9 import edu.umd.cs.findbugs.annotations.Nullable;
10
11 import java.lang.reflect.Member;
12
13 import mockit.internal.BaseInvocation;
14
15 import org.checkerframework.checker.index.qual.NonNegative;
16
17 /**
18 * A context object representing the current invocation to a mocked or faked method/constructor, to be passed as the
19 * <em>first</em> parameter of the corresponding delegate/fake method implementation.
20 * <p>
21 * With the <em>Mocking</em> API, this parameter can appear in delegate methods implemented in {@link Delegate} classes.
22 * With the <em>Faking</em> API, it can appear in {@link Mock @Mock} methods.
23 *
24 * @see #getInvokedInstance()
25 * @see #getInvokedArguments()
26 * @see #getInvocationCount()
27 * @see #getInvocationIndex()
28 * @see #proceed(Object...)
29 * @see <a href="http://jmockit.github.io/tutorial/Mocking.html#delegates" target="tutorial">Tutorial (mocking)</a>
30 * @see <a href="http://jmockit.github.io/tutorial/Faking.html#invocation" target="tutorial">Tutorial (faking)</a>
31 */
32 public class Invocation {
33
34 /** The invoked instance. */
35 @Nullable
36 private final Object invokedInstance;
37
38 /** The invoked arguments. */
39 @NonNull
40 private final Object[] invokedArguments;
41
42 /** The invocation count. */
43 @NonNegative
44 private final int invocationCount;
45
46 /**
47 * For internal use only.
48 *
49 * @param invokedInstance
50 * the invoked instance
51 * @param invokedArguments
52 * the invoked arguments
53 * @param invocationCount
54 * the invocation count
55 */
56 protected Invocation(@Nullable Object invokedInstance, @NonNull Object[] invokedArguments,
57 @NonNegative int invocationCount) {
58 this.invokedInstance = invokedInstance;
59 this.invokedArguments = invokedArguments;
60 this.invocationCount = invocationCount;
61 }
62
63 /**
64 * Returns the instance on which the current invocation was made, or <code>null</code> for a <code>static</code>
65 * method invocation.
66 *
67 * @param <T>
68 * the generic type
69 *
70 * @return the invoked instance
71 */
72 @Nullable
73 public final <T> T getInvokedInstance() {
74 // noinspection unchecked
75 return (T) invokedInstance;
76 }
77
78 /**
79 * Returns the <code>Method</code> or <code>Constructor</code> object corresponding to the target method or
80 * constructor, respectively.
81 *
82 * @param <M>
83 * the generic type
84 *
85 * @return the invoked member
86 */
87 @NonNull
88 public final <M extends Member> M getInvokedMember() {
89 // noinspection unchecked,ClassReferencesSubclass
90 return (M) ((BaseInvocation) this).getRealMember();
91 }
92
93 /**
94 * Returns the actual argument values passed in the invocation to the target method/constructor.
95 *
96 * @return the invoked arguments
97 */
98 @NonNull
99 public final Object[] getInvokedArguments() {
100 return invokedArguments;
101 }
102
103 /**
104 * Returns the current invocation count. The first invocation starts at 1 (one).
105 *
106 * @return the invocation count
107 */
108 @NonNegative
109 public final int getInvocationCount() {
110 return invocationCount;
111 }
112
113 /**
114 * Returns the index for the current invocation. The first invocation starts at 0 (zero). Note that this is
115 * equivalent to {@link #getInvocationCount()} - 1.
116 *
117 * @return the invocation index
118 */
119 public final int getInvocationIndex() {
120 return invocationCount - 1;
121 }
122
123 /**
124 * Allows execution to proceed into the real implementation of the target method/constructor.
125 * <p>
126 * In the case of a method, the real implementation is executed with the argument values originally received or
127 * explicitly given as replacement. Whatever comes out (either a return value or a thrown exception/error) becomes
128 * the result for this execution of the method.
129 * <p>
130 * In the case of a constructor, the real constructor implementation code which comes after the necessary call to
131 * "<code>super</code>" is executed, using the original argument values; replacement arguments are not supported. If
132 * the execution of said code throws an exception or error, it is propagated out to the caller of the target
133 * constructor. Contrary to proceeding into a method, it's not possible to actually execute test code inside the
134 * delegate or fake method after proceeding into the real constructor, nor to proceed into it more than once.
135 *
136 * @param <T>
137 * the return type of the target method
138 * @param replacementArguments
139 * the argument values to be passed to the real method, as replacement for the values received by the
140 * delegate or fake method; if those received values should be passed without replacement, then this
141 * method should be called with no values
142 *
143 * @return the same value returned by the target method, if any
144 *
145 * @throws UnsupportedOperationException
146 * if attempting to proceed into a target method which does not belong to an {@linkplain Injectable
147 * injectable mocked type} nor to a {@linkplain Expectations#Expectations(Object...) partially mocked
148 * object}, into a <code>native</code> method, or into an interface or abstract method
149 *
150 * @see <a href="http://jmockit.github.io/tutorial/Faking.html#proceed" target="tutorial">Tutorial</a>
151 */
152 @Nullable
153 public final <T> T proceed(@Nullable Object... replacementArguments) {
154 // noinspection ClassReferencesSubclass
155 return ((BaseInvocation) this).doProceed(replacementArguments);
156 }
157 }