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