1
2
3
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 }