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