KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > util > DeepClonerTest


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
3  */

4 package com.tc.util;
5
6 import org.apache.commons.lang.builder.EqualsBuilder;
7 import org.apache.commons.lang.builder.HashCodeBuilder;
8
9 import com.tc.test.TCTestCase;
10
11 import java.lang.reflect.Array JavaDoc;
12 import java.util.ArrayList JavaDoc;
13 import java.util.Collection JavaDoc;
14 import java.util.Date JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.HashSet JavaDoc;
17 import java.util.Hashtable JavaDoc;
18 import java.util.Iterator JavaDoc;
19 import java.util.LinkedHashSet JavaDoc;
20 import java.util.LinkedList JavaDoc;
21 import java.util.Map JavaDoc;
22 import java.util.TreeMap JavaDoc;
23 import java.util.TreeSet JavaDoc;
24 import java.util.Vector JavaDoc;
25
26 /**
27  * Unit test for {@link DeepCloner}.
28  */

29 public class DeepClonerTest extends TCTestCase {
30
31   public void testNull() {
32     assertNull(DeepCloner.deepClone(null));
33   }
34
35   public void testValueTypes() {
36     Object JavaDoc[] valueObjects = new Object JavaDoc[] { new String JavaDoc("foo"), new Boolean JavaDoc(true), new Character JavaDoc('V'),
37         new Byte JavaDoc((byte) -57), new Short JavaDoc((short) 12345), new Integer JavaDoc(-234892352), new Long JavaDoc(4912840983148025L),
38         new Float JavaDoc(5.234789e+17), new Double JavaDoc(-2.48925023854e-138), new Date JavaDoc() };
39
40     for (int i = 0; i < valueObjects.length; ++i) {
41       assertSame(valueObjects[i], DeepCloner.deepClone(valueObjects[i]));
42     }
43   }
44
45   public void testNonDeepCloneable() {
46     try {
47       DeepCloner.deepClone(new NonDeepCloneable());
48       fail("Didn't get UOE on non-deep-cloneable");
49     } catch (UnsupportedOperationException JavaDoc uoe) {
50       // ok
51
}
52   }
53
54   private static class NonDeepCloneable {
55     // nothing here
56
}
57
58   private static class MyObject implements DeepCloneable, Comparable JavaDoc {
59     private final String JavaDoc identity;
60     private final String JavaDoc equalsComparison;
61     private Object JavaDoc reference;
62
63     public MyObject(String JavaDoc identity, String JavaDoc equalsComparison) {
64       this.identity = identity;
65       this.equalsComparison = equalsComparison;
66     }
67
68     public MyObject(MyObject source, DeepCloner cloner) {
69       cloner.setClone(source, this);
70       this.identity = source.identity;
71       this.equalsComparison = source.equalsComparison;
72       this.reference = cloner.subClone(source.reference);
73     }
74
75     public void setReference(Object JavaDoc reference) {
76       this.reference = reference;
77     }
78
79     public String JavaDoc identity() {
80       return this.identity;
81     }
82
83     public String JavaDoc equalsComparison() {
84       return this.equalsComparison;
85     }
86
87     public Object JavaDoc reference() {
88       return this.reference;
89     }
90
91     public Object JavaDoc deepClone(DeepCloner cloner) {
92       return new MyObject(this, cloner);
93     }
94
95     public boolean equals(Object JavaDoc that) {
96       if (!(that instanceof MyObject)) return false;
97
98       MyObject myThat = (MyObject) that;
99       return new EqualsBuilder().append(this.equalsComparison, myThat.equalsComparison).isEquals();
100     }
101
102     public int hashCode() {
103       return new HashCodeBuilder().append(this.equalsComparison).toHashCode();
104     }
105
106     public int compareTo(Object JavaDoc o) {
107       return this.equalsComparison.compareTo(((MyObject) o).equalsComparison);
108     }
109   }
110
111   private static class MySubObject extends MyObject {
112     private Object JavaDoc subReference;
113
114     public MySubObject(String JavaDoc identity, String JavaDoc equalsComparison) {
115       super(identity, equalsComparison);
116     }
117
118     public MySubObject(MySubObject source, DeepCloner cloner) {
119       super(source, cloner);
120       this.subReference = cloner.subClone(source.subReference);
121     }
122
123     public Object JavaDoc subReference() {
124       return this.subReference;
125     }
126
127     public Object JavaDoc deepClone(DeepCloner cloner) {
128       return new MySubObject(this, cloner);
129     }
130
131     public void setSubReference(Object JavaDoc subReference) {
132       this.subReference = subReference;
133     }
134   }
135
136   // This class is broken: it does not correctly override deepClone(DeepCloner).
137
private static class MyBrokenSubObject extends MyObject {
138     private Object JavaDoc subReference;
139
140     public MyBrokenSubObject(String JavaDoc identity, String JavaDoc equalsComparison) {
141       super(identity, equalsComparison);
142     }
143
144     public MyBrokenSubObject(MyObject source, DeepCloner cloner) {
145       super(source, cloner);
146     }
147
148     public void setSubReference(Object JavaDoc subReference) {
149       this.subReference = subReference;
150     }
151
152     public Object JavaDoc subReference() {
153       return this.subReference;
154     }
155   }
156
157   private static class MyBrokenSetCloneObject implements DeepCloneable {
158     private Object JavaDoc reference;
159
160     public MyBrokenSetCloneObject() {
161       this.reference = null;
162     }
163
164     private MyBrokenSetCloneObject(MyBrokenSetCloneObject source, DeepCloner cloner) {
165       // Deliberate reversal of arguments here
166
cloner.setClone(this, source);
167       this.reference = cloner.subClone(source);
168     }
169
170     public void setReference(Object JavaDoc reference) {
171       this.reference = reference;
172     }
173
174     public Object JavaDoc reference() {
175       return this.reference;
176     }
177
178     public Object JavaDoc deepClone(DeepCloner cloner) {
179       return new MyBrokenSetCloneObject(this, cloner);
180     }
181   }
182
183   private static class MyNoSetCloneObject implements DeepCloneable {
184     private Object JavaDoc reference;
185
186     public MyNoSetCloneObject() {
187       this.reference = null;
188     }
189
190     private MyNoSetCloneObject(MyNoSetCloneObject source, DeepCloner cloner) {
191       this.reference = cloner.subClone(source);
192     }
193
194     public void setReference(Object JavaDoc reference) {
195       this.reference = reference;
196     }
197
198     public Object JavaDoc reference() {
199       return this.reference;
200     }
201
202     public Object JavaDoc deepClone(DeepCloner cloner) {
203       return new MyNoSetCloneObject(this, cloner);
204     }
205   }
206
207   public void testCircularReference() {
208     MyObject one = new MyObject("a", "b");
209     MyObject two = new MyObject("c", "d");
210
211     one.setReference(two);
212     two.setReference(one);
213
214     MyObject oneClone = (MyObject) DeepCloner.deepClone(one);
215     assertNotSame(one, oneClone);
216     assertNotSame(two, oneClone);
217
218     assertEquals(one, oneClone);
219     assertSame(one.identity(), oneClone.identity());
220     assertSame(one.equalsComparison(), oneClone.equalsComparison());
221
222     MyObject twoClone = (MyObject) oneClone.reference();
223
224     assertNotSame(one, twoClone);
225     assertNotSame(two, twoClone);
226
227     assertEquals(two, twoClone);
228     assertSame(two.identity(), twoClone.identity());
229     assertSame(two.equalsComparison(), twoClone.equalsComparison());
230
231     assertSame(oneClone, twoClone.reference());
232   }
233
234   public void testBrokenSetClone() {
235     MyBrokenSetCloneObject one = new MyBrokenSetCloneObject();
236     MyBrokenSetCloneObject two = new MyBrokenSetCloneObject();
237
238     one.setReference(two);
239     two.setReference(one);
240
241     try {
242       DeepCloner.deepClone(one);
243       fail("Didn't get TCAE on broken setClone() method.");
244     } catch (TCAssertionError tcae) {
245       // ok
246
}
247   }
248   
249   public void testNoSetClone() {
250     MyNoSetCloneObject one = new MyNoSetCloneObject();
251     MyNoSetCloneObject two = new MyNoSetCloneObject();
252     
253     one.setReference(two);
254     two.setReference(one);
255     
256     try {
257       DeepCloner.deepClone(one);
258       fail("Didn't get TCAE on missing setClone() method.");
259     } catch (TCAssertionError tcae) {
260       // ok
261
}
262   }
263
264   public void testSimpleClone() {
265     MyObject obj = new MyObject("a", "b");
266     obj.setReference(new Integer JavaDoc(432));
267
268     MyObject clone = (MyObject) DeepCloner.deepClone(obj);
269
270     assertNotSame(obj, clone);
271     assertEquals(obj, clone);
272     assertSame(obj.identity(), clone.identity());
273     assertSame(obj.equalsComparison(), clone.equalsComparison());
274     assertSame(obj.reference(), clone.reference());
275   }
276
277   public void testClonesReference() {
278     MyObject obj = new MyObject("a", "b");
279     MyObject referredTo = new MyObject("c", "d");
280     obj.setReference(referredTo);
281     referredTo.setReference(new Integer JavaDoc(543));
282
283     MyObject clone = (MyObject) DeepCloner.deepClone(obj);
284
285     assertNotSame(obj, clone);
286     assertEquals(obj, clone);
287     assertSame(obj.identity(), clone.identity());
288     assertSame(obj.equalsComparison(), clone.equalsComparison());
289
290     MyObject referredToClone = (MyObject) clone.reference();
291     assertSame(obj.reference(), referredTo);
292     assertNotSame(referredTo, referredToClone);
293     assertEquals(referredTo, referredToClone);
294     assertSame(referredTo.identity(), referredToClone.identity());
295     assertSame(referredTo.equalsComparison(), referredToClone.equalsComparison());
296     assertSame(referredTo.reference(), referredToClone.reference());
297   }
298
299   public void testDoesNotMultiplyCloneObjects() {
300     // We also give all of these the same equals comparison; this makes sure that we're cloning objects (or returning
301
// references to already-cloned objects) based on identity, not Object.equals().
302
MySubObject a = new MySubObject("a", "x");
303     MyObject b = new MyObject("b", "x");
304     MyObject c = new MyObject("c", "x");
305
306     a.setReference(b);
307     a.setSubReference(c);
308     b.setReference(c);
309
310     MySubObject aClone = (MySubObject) DeepCloner.deepClone(a);
311     MyObject bClone = (MyObject) aClone.reference();
312     MyObject cCloneThroughA = (MyObject) aClone.subReference();
313     MyObject cCloneThroughB = (MyObject) bClone.reference();
314
315     assertNotSame(a, aClone);
316     assertNotSame(b, bClone);
317     assertNotSame(c, cCloneThroughA);
318     assertNotSame(c, cCloneThroughB);
319
320     assertSame(cCloneThroughA, cCloneThroughB);
321     assertEquals(a, aClone);
322     assertEquals(b, bClone);
323     assertEquals(c, cCloneThroughA);
324
325     assertSame(a.identity(), aClone.identity());
326     assertSame(a.equalsComparison(), aClone.equalsComparison());
327     assertSame(b.identity(), bClone.identity());
328     assertSame(b.equalsComparison(), bClone.equalsComparison());
329     assertSame(c.identity(), cCloneThroughA.identity());
330     assertSame(c.equalsComparison(), cCloneThroughA.equalsComparison());
331   }
332
333   public void testBrokenDeepClone() {
334     try {
335       DeepCloner.deepClone(new MyBrokenSubObject("a", "b"));
336       fail("Didn't get TCAE on broken deepClone() method");
337     } catch (TCAssertionError tcae) {
338       // ok
339
}
340   }
341
342   public void testCollections() throws Exception JavaDoc {
343     Collection JavaDoc[] collections = new Collection JavaDoc[] { new LinkedList JavaDoc(), new ArrayList JavaDoc(), new HashSet JavaDoc(),
344         new LinkedHashSet JavaDoc(), new Vector JavaDoc() };
345
346     for (int i = 0; i < collections.length; ++i) {
347       checkCollection(collections[i], false);
348     }
349
350     checkCollection(new TreeSet JavaDoc(), true);
351   }
352
353   public void testMaps() throws Exception JavaDoc {
354     checkMap(new HashMap JavaDoc(), false);
355     checkMap(new TreeMap JavaDoc(), true);
356     checkMap(new Hashtable JavaDoc(), false);
357   }
358
359   public void testArrays() throws Exception JavaDoc {
360     // In DSO instrumentation of Array.get(), if the array is a primitive boolean array, Array.get()
361
// will always return the same Boolean object, i.e., either Boolean.TRUE or Boolean.FALSE.
362
checkPrimitiveArray(new boolean[] { true, false, false, true, false }, false);
363     checkPrimitiveArray(new char[] { 'a', 'x', 'Q' }, true);
364     checkPrimitiveArray(new byte[] { (byte) 43, (byte) -24, (byte) 14 }, true);
365     checkPrimitiveArray(new short[] { (short) 4382, (short) -4257, (short) 1442 }, true);
366     checkPrimitiveArray(new int[] { 432945, -248925, 48932525 }, true);
367     checkPrimitiveArray(new long[] { 4832908402L, -2384908209348092L, 896085049582L }, true);
368     checkPrimitiveArray(new float[] { 4.24983e+12f, -4.2438925e-14f, 1.89384205e+3f }, true);
369     checkPrimitiveArray(new double[] { 1.890810432480e+173, 2.489032842e-132, 8.32849729523e+200 }, true);
370   }
371
372   public void testObjectArray() throws Exception JavaDoc {
373     MySubObject a = new MySubObject("a", "a1");
374     MyObject b = new MyObject("b", "b1");
375     MyObject c = new MyObject("c", "c1");
376     MyObject d = new MyObject("d", "d1");
377
378     a.setReference(b);
379     a.setSubReference(c);
380
381     Integer JavaDoc integer = new Integer JavaDoc(12345);
382     String JavaDoc string = new String JavaDoc("foo");
383
384     LinkedList JavaDoc collection = new LinkedList JavaDoc();
385     collection.add(a);
386     collection.add(d);
387     collection.add(integer);
388
389     Object JavaDoc[] original = new Object JavaDoc[] { a, collection, string };
390     Object JavaDoc[] cloned = (Object JavaDoc[]) DeepCloner.deepClone(original);
391
392     assertEquals(original.length, cloned.length);
393
394     MySubObject aCloneThroughArray = (MySubObject) cloned[0];
395     MyObject bClone = (MyObject) aCloneThroughArray.reference();
396     MyObject cClone = (MyObject) aCloneThroughArray.subReference();
397     LinkedList JavaDoc collectionClone = (LinkedList JavaDoc) cloned[1];
398     String JavaDoc stringClone = (String JavaDoc) cloned[2];
399     MySubObject aCloneThroughCollection = (MySubObject) collectionClone.get(0);
400     MyObject dClone = (MyObject) collectionClone.get(1);
401     Integer JavaDoc integerClone = (Integer JavaDoc) collectionClone.get(2);
402
403     assertNotSame(a, aCloneThroughArray);
404     assertSame(a.identity(), aCloneThroughArray.identity());
405     assertSame(a.equalsComparison(), aCloneThroughArray.equalsComparison());
406
407     assertNotSame(b, bClone);
408     assertSame(b.identity(), bClone.identity());
409     assertSame(b.equalsComparison(), bClone.equalsComparison());
410
411     assertNotSame(c, cClone);
412     assertSame(c.identity(), cClone.identity());
413     assertSame(c.equalsComparison(), cClone.equalsComparison());
414
415     assertNotSame(collection, collectionClone);
416     assertEquals(collection.size(), collectionClone.size());
417
418     assertSame(aCloneThroughArray, aCloneThroughCollection);
419
420     assertNotSame(d, dClone);
421     assertSame(d.identity(), dClone.identity());
422     assertSame(d.equalsComparison(), dClone.equalsComparison());
423
424     assertSame(string, stringClone);
425     assertSame(integer, integerClone);
426   }
427
428   private void checkPrimitiveArray(Object JavaDoc array, boolean differentIdentityCheckRequired) {
429     Object JavaDoc clone = DeepCloner.deepClone(array);
430
431     assertNotSame(array, clone);
432     assertEquals(Array.getLength(array), Array.getLength(clone));
433
434     for (int i = 0; i < Array.getLength(array); ++i) {
435       Object JavaDoc originalValue = Array.get(array, i);
436       Object JavaDoc clonedValue = Array.get(clone, i);
437
438       assertEquals(originalValue, clonedValue);
439       if (differentIdentityCheckRequired) {
440         assertNotSame(originalValue, clonedValue);
441       }
442     }
443   }
444
445   private void checkMap(Map JavaDoc map, boolean requiresOrder) {
446     MyObject aKey = new MyObject("k", "k1");
447     MyObject aKeyRef = new MyObject("ak", "ak1");
448     aKey.setReference(aKeyRef);
449
450     MyObject bKey = new MyObject("b", "b1");
451     bKey.setReference(aKeyRef);
452
453     MyObject cKey = new MyObject("c", "c1");
454
455     MySubObject a = new MySubObject("a", "b");
456     MyObject ref = new MyObject("ref", "ref1");
457     MyObject subRef = new MyObject("subRef", "subRef1");
458     Integer JavaDoc integer = new Integer JavaDoc(42);
459     String JavaDoc string = new String JavaDoc("foo");
460
461     a.setReference(ref);
462     a.setSubReference(subRef);
463
464     LinkedList JavaDoc list = new LinkedList JavaDoc();
465     list.add(ref);
466     list.add(string);
467
468     map.put(aKey, a);
469     if (!requiresOrder) {
470       map.put(bKey, list);
471       map.put(cKey, integer);
472     }
473
474     Map JavaDoc cloned = (Map JavaDoc) DeepCloner.deepClone(map);
475
476     assertNotSame(map, cloned);
477
478     Iterator JavaDoc iter = cloned.entrySet().iterator();
479     MyObject aCloneRef = null;
480     boolean haveA = false, haveB = false, haveC = false;
481
482     while (iter.hasNext()) {
483       Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
484       MyObject key = (MyObject) entry.getKey();
485       Object JavaDoc value = entry.getValue();
486
487       if (key.equals(aKey)) {
488         assertNotSame(aKey, key);
489         assertSame(aKey.identity(), key.identity());
490         assertSame(aKey.equalsComparison(), key.equalsComparison());
491
492         MyObject keyRef = (MyObject) key.reference();
493         assertNotSame(aKeyRef, keyRef);
494         assertSame(aKeyRef.identity(), keyRef.identity());
495         assertSame(aKeyRef.equalsComparison(), keyRef.equalsComparison());
496
497         MySubObject aClone = (MySubObject) value;
498         MyObject thisACloneRef = (MyObject) aClone.reference();
499         if (aCloneRef != null) assertSame(aCloneRef, thisACloneRef);
500         else aCloneRef = thisACloneRef;
501         MyObject aCloneSubRef = (MyObject) aClone.subReference();
502
503         assertNotSame(a, aClone);
504         assertSame(a.identity(), aClone.identity());
505         assertSame(a.equalsComparison(), aClone.equalsComparison());
506
507         assertNotSame(ref, aCloneRef);
508         assertSame(ref.identity(), aCloneRef.identity());
509         assertSame(ref.equalsComparison(), aCloneRef.equalsComparison());
510         assertSame(ref.reference(), aCloneRef.reference());
511
512         assertNotSame(subRef, aCloneSubRef);
513         assertSame(subRef.identity(), aCloneSubRef.identity());
514         assertSame(subRef.equalsComparison(), aCloneSubRef.equalsComparison());
515         assertSame(subRef.reference(), aCloneSubRef.reference());
516
517         haveA = true;
518       } else if (key.equals(bKey)) {
519         assertNotSame(bKey, key);
520         assertSame(bKey.identity(), key.identity());
521         assertSame(bKey.equalsComparison(), key.equalsComparison());
522
523         LinkedList JavaDoc listClone = (LinkedList JavaDoc) value;
524         MyObject thisACloneRef = (MyObject) listClone.get(0);
525         if (aCloneRef != null) assertSame(aCloneRef, thisACloneRef);
526         else aCloneRef = thisACloneRef;
527         assertSame(string, list.get(1));
528
529         haveB = true;
530       } else if (key.equals(cKey)) {
531         assertNotSame(cKey, key);
532         assertSame(cKey.identity(), key.identity());
533         assertSame(cKey.equalsComparison(), key.equalsComparison());
534
535         assertSame(integer, value);
536
537         haveC = true;
538       } else {
539         fail("Unknown key: " + key);
540       }
541     }
542
543     assertTrue(haveA);
544     assertEquals(!requiresOrder, haveB);
545     assertEquals(!requiresOrder, haveC);
546   }
547
548   private void checkCollection(Collection JavaDoc collection, boolean requiresOrder) {
549     MySubObject a = new MySubObject("a", "b");
550     MyObject ref = new MyObject("ref", "ref1");
551     MyObject subRef = new MyObject("subRef", "subRef1");
552     Integer JavaDoc integer = new Integer JavaDoc(42);
553     String JavaDoc string = new String JavaDoc("foo");
554
555     a.setReference(ref);
556     a.setSubReference(subRef);
557
558     LinkedList JavaDoc list = new LinkedList JavaDoc();
559     list.add(ref);
560     list.add(string);
561
562     collection.add(a);
563     if (!requiresOrder) {
564       // LinkedLists aren't Comparable, and Integers (obviously) really don't like being compared to anything but
565
// Integers.
566
collection.add(list);
567       collection.add(integer);
568     }
569
570     Collection JavaDoc cloned = (Collection JavaDoc) DeepCloner.deepClone(collection);
571
572     assertNotSame(collection, cloned);
573
574     Iterator JavaDoc clonedIter = cloned.iterator();
575     MySubObject clonedA = null;
576     LinkedList JavaDoc clonedList = null;
577     Integer JavaDoc clonedInteger = null;
578
579     while (clonedIter.hasNext()) {
580       Object JavaDoc next = clonedIter.next();
581       if (next instanceof MySubObject) {
582         assertNull(clonedA);
583         clonedA = (MySubObject) next;
584       } else if (next instanceof LinkedList JavaDoc) {
585         assertNull(clonedList);
586         clonedList = (LinkedList JavaDoc) next;
587       } else if (next instanceof Integer JavaDoc) {
588         assertNull(clonedInteger);
589         clonedInteger = (Integer JavaDoc) next;
590       } else {
591         fail("Unknown object in collection: " + next);
592       }
593     }
594
595     assertNotSame(a, clonedA);
596     if (!requiresOrder) {
597       assertNotSame(list, clonedList);
598       assertSame(integer, clonedInteger);
599     }
600
601     MyObject clonedRef = (MyObject) clonedA.reference();
602     MyObject clonedSubRef = (MyObject) clonedA.subReference();
603
604     assertNotSame(ref, clonedRef);
605     assertSame(ref.identity(), clonedRef.identity());
606     assertSame(ref.equalsComparison(), clonedRef.equalsComparison());
607     assertNull(ref.reference());
608
609     assertNotSame(subRef, clonedSubRef);
610     assertSame(subRef.identity(), clonedSubRef.identity());
611     assertSame(subRef.equalsComparison(), clonedSubRef.equalsComparison());
612     assertNull(subRef.reference());
613
614     if (!requiresOrder) {
615       assertSame(clonedRef, clonedList.get(0));
616       assertSame(string, clonedList.get(1));
617       assertEquals(2, clonedList.size());
618     }
619   }
620
621 }
622
Popular Tags