View Javadoc
1   /*
2    * MIT License
3    * Copyright (c) 2006-2025 JMockit developers
4    * See LICENSE file for full license text.
5    */
6   package mockit.internal.expectations.invocation;
7   
8   import edu.umd.cs.findbugs.annotations.NonNull;
9   import edu.umd.cs.findbugs.annotations.Nullable;
10  
11  import java.lang.reflect.Array;
12  import java.util.Iterator;
13  
14  import mockit.Delegate;
15  import mockit.internal.expectations.invocation.InvocationResult.DeferredResults;
16  import mockit.internal.expectations.invocation.InvocationResult.ReturnValueResult;
17  import mockit.internal.expectations.invocation.InvocationResult.ThrowableResult;
18  
19  import org.checkerframework.checker.index.qual.NonNegative;
20  
21  public final class InvocationResults {
22      @NonNull
23      private final ExpectedInvocation invocation;
24      @NonNull
25      private final InvocationConstraints constraints;
26      @Nullable
27      private InvocationResult currentResult;
28      @Nullable
29      private InvocationResult lastResult;
30      @NonNegative
31      private int resultCount;
32  
33      public InvocationResults(@NonNull ExpectedInvocation invocation, @NonNull InvocationConstraints constraints) {
34          this.invocation = invocation;
35          this.constraints = constraints;
36      }
37  
38      public void addReturnValue(@Nullable Object value) {
39          if (value instanceof Delegate) {
40              addDelegatedResult((Delegate<?>) value);
41          } else {
42              addNewReturnValueResult(value);
43          }
44      }
45  
46      public void addDelegatedResult(@NonNull Delegate<?> delegate) {
47          InvocationResult result = new DelegatedResult(invocation, delegate);
48          addResult(result);
49      }
50  
51      private void addNewReturnValueResult(@Nullable Object value) {
52          InvocationResult result = new ReturnValueResult(value);
53          addResult(result);
54      }
55  
56      public void addReturnValueResult(@Nullable Object value) {
57          addNewReturnValueResult(value);
58      }
59  
60      public void addReturnValues(@NonNull Object... values) {
61          for (Object value : values) {
62              addReturnValue(value);
63          }
64      }
65  
66      void addResults(@NonNull Object array) {
67          int n = Array.getLength(array);
68  
69          for (int i = 0; i < n; i++) {
70              Object value = Array.get(array, i);
71              addConsecutiveResult(value);
72          }
73      }
74  
75      private void addConsecutiveResult(@Nullable Object result) {
76          if (result instanceof Throwable) {
77              addThrowable((Throwable) result);
78          } else {
79              addReturnValue(result);
80          }
81      }
82  
83      void addResults(@NonNull Iterable<?> values) {
84          for (Object value : values) {
85              addConsecutiveResult(value);
86          }
87      }
88  
89      void addDeferredResults(@NonNull Iterator<?> values) {
90          InvocationResult result = new DeferredResults(values);
91          addResult(result);
92          constraints.setUnlimitedMaxInvocations();
93      }
94  
95      public void addThrowable(@NonNull Throwable t) {
96          addResult(new ThrowableResult(t));
97      }
98  
99      private void addResult(@NonNull InvocationResult result) {
100         resultCount++;
101         constraints.adjustMaxInvocations(resultCount);
102 
103         if (currentResult == null) {
104             currentResult = result;
105         } else {
106             assert lastResult != null;
107             lastResult.next = result;
108         }
109 
110         lastResult = result;
111     }
112 
113     @Nullable
114     public Object produceResult(@Nullable Object invokedObject, @NonNull Object[] invocationArgs) throws Throwable {
115         InvocationResult resultToBeProduced = currentResult;
116 
117         if (resultToBeProduced == null) {
118             return null;
119         }
120 
121         InvocationResult nextResult = resultToBeProduced.next;
122 
123         if (nextResult != null) {
124             currentResult = nextResult;
125         }
126 
127         return resultToBeProduced.produceResult(invokedObject, invocation, constraints, invocationArgs);
128     }
129 }