1 package org.pojomatic.internal;
2
3 import static org.testng.Assert.*;
4
5 import java.lang.annotation.Annotation;
6 import java.lang.reflect.Array;
7 import java.util.ArrayList;
8 import java.util.Arrays;
9 import java.util.List;
10 import java.util.Objects;
11
12 import org.pojomatic.annotations.SkipArrayCheck;
13 import org.pojomatic.diff.Difference;
14 import org.pojomatic.diff.Differences;
15 import org.pojomatic.diff.NoDifferences;
16 import org.pojomatic.diff.PropertyDifferences;
17 import org.pojomatic.diff.ValueDifference;
18 import org.pojomatic.internal.factory.PojoDescriptor;
19 import org.pojomatic.internal.factory.PojoFactory;
20 import org.pojomatic.internal.factory.PropertyDescriptor;
21 import org.testng.annotations.Test;
22
23 import com.google.common.collect.Iterables;
24
25 public class PropertyTypeTest {
26
27 @Test(dataProvider = "types", dataProviderClass = TypeProviders.class)
28 public void testHashCode(Type type) {
29 PojoFactory pojoFactory = new PojoFactory(new PojoDescriptor(new PropertyDescriptor(type.getClazz())));
30 for (Object value: type.getSampleValues()) {
31 checkHashCode(pojoFactory, value, type.hashCode(value));
32 }
33 }
34
35 @Test(dataProvider = "arrayTypes", dataProviderClass = TypeProviders.class)
36 public void testArrayAsObjectHashCode(Type type, boolean skipArrayCheck) {
37 PojoFactory pojoFactory = new PojoFactory(
38 new PojoDescriptor(new PropertyDescriptor(Object.class, extraAnnotations(skipArrayCheck))));
39 for (Object value: type.getSampleValues()) {
40 int propertyHashCode = skipArrayCheck
41 ? Objects.hashCode(value)
42 : type.deepHashCode(value);
43
44 checkHashCode(pojoFactory, value, propertyHashCode);
45 }
46 }
47
48 @Test(dataProvider = "arrayTypes", dataProviderClass = TypeProviders.class)
49 public void testArrayAsArrayHashCode(Type type, boolean skipArrayCheck) {
50 PojoFactory pojoFactory = new PojoFactory(
51 new PojoDescriptor(new PropertyDescriptor(type.getClazz(), extraAnnotations(skipArrayCheck))));
52 for (Object value: type.getSampleValues()) {
53 checkHashCode(pojoFactory, value, type.deepHashCode(value));
54 }
55 }
56
57 @Test(dataProvider = "types", dataProviderClass = TypeProviders.class)
58 public void testToString(Type type) {
59 PojoFactory pojoFactory = new PojoFactory(new PojoDescriptor(new PropertyDescriptor(type.getClazz())));
60 for (Object value: type.getSampleValues()) {
61 checkToString(pojoFactory, value, type.toString(value));
62 }
63 }
64
65 @Test(dataProvider = "arrayTypes", dataProviderClass = TypeProviders.class)
66 public void testArrayAsObjectToString(Type type, boolean skipArrayCheck) {
67 PojoFactory pojoFactory = new PojoFactory(
68 new PojoDescriptor(new PropertyDescriptor(Object.class, extraAnnotations(skipArrayCheck))));
69 for (Object value: type.getSampleValues()) {
70 String expectedPropertyValue = skipArrayCheck ? Objects.toString(value) : type.deepToString(value);
71 checkToString(pojoFactory, value, expectedPropertyValue);
72 }
73 }
74
75 @Test(dataProvider = "arrayTypes", dataProviderClass = TypeProviders.class)
76 public void testArrayAsArrayToString(Type type, boolean skipArrayCheck) {
77 PojoFactory pojoFactory = new PojoFactory(
78 new PojoDescriptor(new PropertyDescriptor(type.getClazz(), extraAnnotations(skipArrayCheck))));
79 for (Object value: type.getSampleValues()) {
80 checkToString(pojoFactory, value, type.deepToString(value));
81 }
82 }
83
84 @Test(dataProvider = "types", dataProviderClass = TypeProviders.class)
85 public void testEqualsAndDiff(Type type) {
86 PojoFactory pojoFactory = new PojoFactory(new PojoDescriptor(new PropertyDescriptor(type.getClazz())));
87 for (Object value1: type.getSampleValues()) {
88 Object pojo1 = pojoFactory.create(value1);
89 for (Object value2: type.getSampleValues()) {
90 boolean expectedToBeEqual = value1 == null ? value2 == null : value1.equals(value2);
91 Object pojo2 = pojoFactory.create(value2);
92 checkEqualsAndDiff(expectedToBeEqual, pojoFactory, value1, value2, pojo1, pojo2);
93
94 }
95 assertFalse(
96 pojoFactory.pojomator().doEquals(pojo1, null),
97 "type: " + type.getClazz() + ", value1: " + value1);
98 }
99 }
100
101 @Test(dataProvider = "annotations", dataProviderClass = TypeProviders.class)
102 public void testMixedTypesAsObjectEqualsAndDiff(boolean skipArrayCheck) {
103 PojoFactory pojoFactory = new PojoFactory(
104 new PojoDescriptor(new PropertyDescriptor(Object.class, extraAnnotations(skipArrayCheck))));
105 Iterable<Type> allTypes =
106 Iterables.concat(Arrays.asList(BaseType.OBJECT), TypeProviders.simpleArrays(), TypeProviders.doubleArrays());
107 List<Object> allValues = new ArrayList<>();
108 for (Type type: allTypes) {
109 allValues.addAll(type.getSampleValues());
110 }
111
112
113
114 for (Object value1: allValues) {
115 Object pojo1 = pojoFactory.create(value1);
116 for (Object value2: allValues) {
117 testMixedTypesAsObjectEqualsAndDiffWorker(skipArrayCheck, pojoFactory, value1, pojo1, value2);
118 }
119 }
120 }
121
122 private void testMixedTypesAsObjectEqualsAndDiffWorker(boolean skipArrayCheck,
123 PojoFactory pojoFactory, Object value1, Object pojo1, Object value2) {
124 Object value2PossibleClone = maybeCloneObject(value2);
125 Object pojo2 = pojoFactory.create(value2PossibleClone);;
126 boolean expectedToBeEqual = Objects.equals(value1, value2PossibleClone)
127 || !skipArrayCheck && value1 == value2;
128
129 checkEqualsAndDiff(expectedToBeEqual, pojoFactory, value1, value2PossibleClone, pojo1, pojo2);
130 }
131
132 @Test(dataProvider = "arrayTypes", dataProviderClass = TypeProviders.class)
133 public void testArrayAsObjectEqualsAndDiff(Type type, boolean skipArrayCheck) {
134 PojoFactory pojoFactory = new PojoFactory(
135 new PojoDescriptor(new PropertyDescriptor(Object.class, extraAnnotations(skipArrayCheck))));
136 for (Object value1: type.getSampleValues()) {
137 Object pojo1 = pojoFactory.create(value1);
138 for (Object value2: type.getSampleValues()) {
139
140
141 boolean expectedToBeEqual = (value1 == value2) && (value1 == null || (!skipArrayCheck));
142 Object pojo2 = pojoFactory.create(cloneArray(value2, !skipArrayCheck));
143 checkEqualsAndDiff(expectedToBeEqual, pojoFactory, value1, value2, pojo1, pojo2);
144 if (skipArrayCheck) {
145
146 checkEqualsAndDiff(value1 == value2, pojoFactory, value1, value2, pojo1, pojoFactory.create(value2));
147 }
148 }
149 assertFalse(
150 pojoFactory.pojomator().doEquals(pojo1, null),
151 "type: " + type.getClazz() + ", value1: " + value1);
152 }
153 }
154
155 @Test(dataProvider = "arrayTypes", dataProviderClass = TypeProviders.class)
156 public void testArrayAsArrayEqualsAndDiff(Type type, boolean skipArrayCheck) {
157 PojoFactory pojoFactory = new PojoFactory(
158 new PojoDescriptor(new PropertyDescriptor(type.getClazz(), extraAnnotations(skipArrayCheck))));
159 for (Object value1: type.getSampleValues()) {
160 for (Object value2: type.getSampleValues()) {
161 Object pojo1 = pojoFactory.create(value1);
162 Object pojo2 = pojoFactory.create(cloneArray(value2, true));
163 boolean expectedToBeEqual = (value1 == value2);
164 checkEqualsAndDiff(expectedToBeEqual, pojoFactory, value1, value2, pojo1, pojo2);
165 }
166 }
167 }
168
169
170
171
172
173
174 @Test(dataProvider = "deepArrayTypes", dataProviderClass = TypeProviders.class)
175 public void testDeepArrayAsObjectEqualsAndDiff(Type type, boolean skipArrayCheck) {
176 PojoFactory pojoFactory = new PojoFactory(
177 new PojoDescriptor(new PropertyDescriptor(Object.class, extraAnnotations(skipArrayCheck))));
178 for (Object value1: type.getSampleValues()) {
179 for (Object value2: type.getSampleValues()) {
180
181
182
183 boolean expectedToBeEqual = (value1 == value2) && (value1 == null || ! skipArrayCheck);
184 Object pojo1 = pojoFactory.create(value1);
185 Object pojo2 = pojoFactory.create(cloneArray(value2, true));
186 checkEqualsAndDiff(expectedToBeEqual, pojoFactory, value1, value2, pojo1, pojo2);
187 }
188 }
189 }
190
191
192
193
194
195
196 @Test(dataProvider = "deepArrayTypes", dataProviderClass = TypeProviders.class)
197 public void testDeepArrayAsArrayEquals(Type type, boolean skipArrayCheck) {
198 PojoFactory pojoFactory = new PojoFactory(
199 new PojoDescriptor(new PropertyDescriptor(type.getClazz(), extraAnnotations(skipArrayCheck))));
200 for (Object value1: type.getSampleValues()) {
201 for (Object value2: type.getSampleValues()) {
202
203
204
205
206 Object pojo1 = pojoFactory.create(value1);
207 Object pojo2 = pojoFactory.create(cloneArray(value2, true));
208 boolean expectedToBeEqual = value1 == value2;
209 checkEqualsAndDiff(expectedToBeEqual, pojoFactory, value1, value2, pojo1, pojo2);
210 }
211 }
212 }
213
214 @Test(dataProvider = "deepArrayTypes", dataProviderClass = TypeProviders.class)
215 public void testDeepArraysAsShallowArraysEqualsAndDiff(Type type, boolean skipArrayCheck) {
216 PojoFactory pojoFactory = new PojoFactory(
217 new PojoDescriptor(new PropertyDescriptor(Object[].class, extraAnnotations(skipArrayCheck))));
218 for (Object value1: type.getSampleValues()) {
219 for (Object value2: type.getSampleValues()) {
220
221
222
223
224 Object pojo1 = pojoFactory.create(value1);
225 Object pojo2 = pojoFactory.create(cloneArray(value2, true));
226 boolean expectedToBeEqual = value1 == value2;
227 checkEqualsAndDiff(expectedToBeEqual, pojoFactory, value1, value2, pojo1, pojo2);
228 }
229 }
230 }
231
232 @Test(dataProvider = "deepArrayTypes", dataProviderClass = TypeProviders.class)
233 public void testDeepArraysAsShallowArraysToString(Type type, boolean skipArrayCheck) {
234 PojoFactory pojoFactory = new PojoFactory(
235 new PojoDescriptor(new PropertyDescriptor(Object[].class, extraAnnotations(skipArrayCheck))));
236 for (Object value: type.getSampleValues()) {
237 checkToString(pojoFactory, value, type.deepToString(value));
238 }
239 }
240
241 @Test(dataProvider = "annotations", dataProviderClass = TypeProviders.class)
242 public void testMixedTypesAsObjectArrayEqualsAndDiff(boolean skipArrayCheck) {
243 PojoFactory pojoFactory = new PojoFactory(
244 new PojoDescriptor(new PropertyDescriptor(Object[].class, extraAnnotations(skipArrayCheck))));
245 Iterable<Type> allTypes =
246 Iterables.concat(Arrays.asList(new ArrayType(BaseType.OBJECT)), TypeProviders.doubleArrays());
247 List<Object> allValues = new ArrayList<>();
248 for (Type type: allTypes) {
249 allValues.addAll(type.getSampleValues());
250 }
251
252
253
254 for (Object value1: allValues) {
255 Object pojo1 = pojoFactory.create(value1);
256 for (Object value2: allValues) {
257 testMixedTypesAsObjectEqualsAndDiffWorker(false, pojoFactory, value1, pojo1, value2);
258 }
259 }
260 }
261
262
263 @SuppressWarnings("unchecked")
264 private Class<? extends Annotation>[] extraAnnotations(boolean skipArrayCheck) {
265 List<Class<? extends Annotation>> classes = new ArrayList<>();
266 if (skipArrayCheck) {
267 classes.add(SkipArrayCheck.class);
268 }
269 return classes.toArray(new Class[0]);
270 }
271
272 private void checkHashCode(PojoFactory pojoFactory, Object value,
273 int propertyHashCode) {
274 assertEquals(
275 pojoFactory.pojomator().doHashCode(pojoFactory.create(value)),
276 31 + propertyHashCode,
277 label(value));
278 }
279
280 private void checkToString(PojoFactory pojoFactory, Object value,
281 String expectedPropertyValue) {
282 assertEquals(pojoFactory.pojomator().doToString(pojoFactory.create(value)), "Pojo{x: {" + expectedPropertyValue + "}}", label(value));
283 }
284
285 private void checkEqualsAndDiff(boolean expectedToBeEqual, PojoFactory pojoFactory,
286 Object value1, Object value2, Object pojo1, Object pojo2) {
287 if (pojoFactory.pojomator().doEquals(pojo1, pojo2) != expectedToBeEqual)
288 assertEquals(pojoFactory.pojomator().doEquals(pojo1, pojo2), expectedToBeEqual, label(value1, value2));
289 assertEquals(pojoFactory.pojomator().doDiff(pojo1, pojo2), expectedDifferences(expectedToBeEqual, value1, value2), label(value1, value2));
290 }
291
292
293
294
295
296
297
298
299 private Differences expectedDifferences(boolean expectedToBeEqual,
300 Object value1, Object value2) {
301 return expectedToBeEqual
302 ? NoDifferences.getInstance()
303 : new PropertyDifferences(Arrays.<Difference>asList(new ValueDifference("x", value1, value2)));
304 }
305
306 private String label(Object value1, Object value2) {
307 return "value1: " + labelString(value1) + ", value2: " + labelString(value2);
308 }
309
310 private String label(Object value) {
311 return "value: " + labelString(value);
312 }
313
314 private String labelString(Object value) {
315 if (value == null) {
316 return "null";
317 }
318 else {
319 return possibleArrayToList(value) + "(" + value.getClass().getName() + ")";
320 }
321 }
322
323
324
325
326
327 private Object possibleArrayToList(Object value) {
328 if (value == null || ! value.getClass().isArray()) {
329 return value;
330 }
331 List<Object> result = new ArrayList<>();
332 for (int i = 0; i < Array.getLength(value); i++) {
333 result.add(possibleArrayToList(Array.get(value, i)));
334 }
335 return result;
336 }
337
338 private Object maybeCloneObject(Object object) {
339 if (object == null) {
340 return null;
341 }
342 if (object.getClass().isArray()) {
343 return cloneArray(object, true);
344 }
345 else if (object instanceof String) {
346 return new String((String) object);
347 }
348 else {
349 return object;
350 }
351 }
352
353 private Object cloneArray(Object array, boolean deep) {
354 if (array == null) {
355 return null;
356 }
357 Object clone = Array.newInstance(array.getClass().getComponentType(), Array.getLength(array));
358 for (int i = 0; i < Array.getLength(array); i++) {
359 Object element = Array.get(array, i);
360 if (deep && element != null && element.getClass().isArray()) {
361 element = cloneArray(element, deep);
362 }
363 Array.set(clone, i, element);
364 }
365 return clone;
366 }
367 }