1
2
3
4
5 package mockit.internal.expectations.argumentMatching;
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.lang.reflect.Method;
12
13 import mockit.internal.util.ObjectMethods;
14
15 public final class ArgumentMismatch {
16 @NonNull
17 private final StringBuilder out = new StringBuilder(50);
18 @Nullable
19 private String parameterType;
20
21 @Nullable
22 public String getParameterType() {
23 return parameterType;
24 }
25
26 @Override
27 public String toString() {
28 return out.toString();
29 }
30
31 @NonNull
32 public ArgumentMismatch append(char c) {
33 out.append(c);
34 return this;
35 }
36
37 @NonNull
38 public ArgumentMismatch append(int i) {
39 out.append(i);
40 return this;
41 }
42
43 @NonNull
44 public ArgumentMismatch append(double d) {
45 out.append(d);
46 return this;
47 }
48
49 @NonNull
50 public ArgumentMismatch append(@Nullable CharSequence str) {
51 out.append(str);
52 return this;
53 }
54
55 public void appendFormatted(@Nullable String parameterTypeName, @Nullable Object argumentValue,
56 @Nullable ArgumentMatcher<?> matcher) {
57 if (matcher == null) {
58 appendFormatted(argumentValue);
59 } else {
60 parameterType = parameterTypeName;
61 matcher.writeMismatchPhrase(this);
62 }
63 }
64
65 @SuppressWarnings("OverlyComplexMethod")
66 void appendFormatted(@Nullable Object value) {
67 if (value == null) {
68 out.append("null");
69 } else if (value instanceof CharSequence) {
70 appendCharacters((CharSequence) value);
71 } else if (value instanceof Character) {
72 out.append('\'');
73 appendEscapedOrPlainCharacter('\'', (Character) value);
74 out.append('\'');
75 } else if (value instanceof Byte) {
76 out.append(value).append('b');
77 } else if (value instanceof Short) {
78 out.append(value).append('s');
79 } else if (value instanceof Long) {
80 out.append(value).append('L');
81 } else if (value instanceof Float) {
82 out.append(value).append('F');
83 } else if (value instanceof Number || value instanceof Boolean) {
84 out.append(value);
85 } else if (value.getClass().isArray()) {
86 appendArray(value);
87 } else if (value instanceof ArgumentMatcher) {
88 ((ArgumentMatcher<?>) value).writeMismatchPhrase(this);
89 } else {
90 appendArbitraryArgument(value);
91 }
92 }
93
94 private void appendArray(@NonNull Object array) {
95 out.append('[');
96 String separator = "";
97
98 for (int i = 0, n = Array.getLength(array); i < n; i++) {
99 Object nextValue = Array.get(array, i);
100 out.append(separator);
101 appendFormatted(nextValue);
102 separator = ", ";
103 }
104
105 out.append(']');
106 }
107
108 private void appendCharacters(@NonNull CharSequence characters) {
109 out.append('"');
110
111 for (int i = 0, n = characters.length(); i < n; i++) {
112 char c = characters.charAt(i);
113 appendEscapedOrPlainCharacter('"', c);
114 }
115
116 out.append('"');
117 }
118
119 private void appendEscapedOrPlainCharacter(char quoteCharacter, char c) {
120 if (c == quoteCharacter) {
121 out.append('\\').append(c);
122 } else {
123 switch (c) {
124 case '\t':
125 out.append("\\t");
126 break;
127 case '\n':
128 out.append("\\n");
129 break;
130 case '\r':
131 out.append("\\r");
132 break;
133 default:
134 out.append(c);
135 }
136 }
137 }
138
139 private void appendArbitraryArgument(@NonNull Object value) {
140 Class<?> valueClass = value.getClass();
141
142 Method toStringMethod;
143 try {
144 toStringMethod = valueClass.getMethod("toString");
145 } catch (NoSuchMethodException ignored) {
146 return;
147 }
148
149 if (toStringMethod.getDeclaringClass() == Object.class) {
150 out.append(value);
151 } else {
152 String valueAsString = value.toString();
153
154 if (valueAsString != null && !valueAsString.isEmpty()) {
155 appendCharacters(valueAsString);
156 } else {
157 out.append(ObjectMethods.objectIdentity(value));
158 }
159 }
160 }
161
162 public void appendFormatted(@NonNull Object[] values) {
163 String separator = "";
164
165 for (Object value : values) {
166 append(separator).appendFormatted(value);
167 separator = ", ";
168 }
169 }
170 }