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;
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.ArrayList;
12  import java.util.Collection;
13  import java.util.Collections;
14  import java.util.Iterator;
15  import java.util.LinkedHashSet;
16  import java.util.List;
17  import java.util.Set;
18  import java.util.SortedSet;
19  import java.util.TreeSet;
20  
21  final class SequenceOfReturnValues {
22      @NonNull
23      private final Expectation expectation;
24      @NonNull
25      private final Class<?> returnType;
26      @Nullable
27      private final Object firstValue;
28      @NonNull
29      private final Object[] remainingValues;
30  
31      SequenceOfReturnValues(@NonNull Expectation expectation, @Nullable Object firstValue,
32              @NonNull Object[] remainingValues) {
33          this.expectation = expectation;
34          returnType = expectation.getReturnType();
35          this.firstValue = firstValue;
36          this.remainingValues = remainingValues;
37      }
38  
39      boolean addResultWithSequenceOfValues() {
40          boolean added = false;
41  
42          if (returnType != void.class) {
43              if (returnType.isArray()) {
44                  added = addValuesInArrayIfApplicable();
45              } else if (Iterator.class.isAssignableFrom(returnType)) {
46                  added = addValuesInIteratorIfApplicable();
47              } else if (Iterable.class.isAssignableFrom(returnType)) {
48                  added = addValuesInIterableIfApplicable();
49              }
50          }
51  
52          return added;
53      }
54  
55      private boolean addValuesInArrayIfApplicable() {
56          if (firstValue == null || !firstValue.getClass().isArray()) {
57              addArrayAsReturnValue();
58              return true;
59          }
60  
61          return false;
62      }
63  
64      private void addArrayAsReturnValue() {
65          Class<?> elementType = returnType.getComponentType();
66          int n = 1 + remainingValues.length;
67          Object values = Array.newInstance(elementType, n);
68          setArrayElement(elementType, values, 0, firstValue);
69  
70          for (int i = 1; i < n; i++) {
71              setArrayElement(elementType, values, i, remainingValues[i - 1]);
72          }
73  
74          expectation.getResults().addReturnValue(values);
75      }
76  
77      private static void setArrayElement(Class<?> elementType, Object array, int index, @Nullable Object value) {
78          Object arrayValue = value;
79  
80          if (value != null) {
81              if (elementType == byte.class || elementType == Byte.class) {
82                  arrayValue = ((Number) value).byteValue();
83              } else if (elementType == short.class || elementType == Short.class) {
84                  arrayValue = ((Number) value).shortValue();
85              }
86          }
87  
88          Array.set(array, index, arrayValue);
89      }
90  
91      private boolean addValuesInIteratorIfApplicable() {
92          if (firstValue == null || !Iterator.class.isAssignableFrom(firstValue.getClass())) {
93              List<Object> values = new ArrayList<>(1 + remainingValues.length);
94              addAllValues(values);
95              expectation.getResults().addReturnValue(values.iterator());
96              return true;
97          }
98  
99          return false;
100     }
101 
102     private void addAllValues(@NonNull Collection<Object> values) {
103         values.add(firstValue);
104         Collections.addAll(values, remainingValues);
105     }
106 
107     private boolean addValuesInIterableIfApplicable() {
108         if (firstValue == null || !Iterable.class.isAssignableFrom(firstValue.getClass())) {
109             Collection<Object> values;
110 
111             if (returnType.isAssignableFrom(List.class)) {
112                 values = new ArrayList<>(1 + remainingValues.length);
113             } else if (returnType.isAssignableFrom(Set.class)) {
114                 values = new LinkedHashSet<>(1 + remainingValues.length);
115             } else if (returnType.isAssignableFrom(SortedSet.class)) {
116                 values = new TreeSet<>();
117             } else {
118                 return false;
119             }
120 
121             addReturnValues(values);
122             return true;
123         }
124 
125         return false;
126     }
127 
128     private void addReturnValues(@NonNull Collection<Object> values) {
129         addAllValues(values);
130         expectation.getResults().addReturnValue(values);
131     }
132 }