package com.rits.tests.cloning; import com.rits.cloning.Cloner; import com.rits.cloning.FastClonerHashMap; import com.rits.cloning.Immutable; import com.rits.tests.cloning.TestCloner.SynthOuter.Inner; import com.rits.tests.cloning.domain.A; import com.rits.tests.cloning.domain.B; import com.rits.tests.cloning.domain.F; import com.rits.tests.cloning.domain.G; import junit.framework.TestCase; import java.lang.annotation.Retention; import java.lang.annotation.Target; import java.util.*; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * @author kostantinos.kougios * * 18 Sep 2008 */ public class TestCloner extends TestCase { private final Cloner cloner = new Cloner(); { cloner.setDumpClonedClasses(false); } @Target(TYPE) @Retention(RUNTIME) private @interface MyImmutable { } @MyImmutable static private class MyAX { } public void testCalendarTimezone() { TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles"); Calendar c = Calendar.getInstance(timeZone); Calendar cloned = cloner.deepClone(c); assertEquals(timeZone, cloned.getTimeZone()); } public void testCloneEnumInMapIssue20() { Map<Integer, TestEnum> m = new HashMap<Integer, TestEnum>(); m.put(1, TestEnum.A); m.put(2, TestEnum.B); m.put(3, TestEnum.C); Map<Integer, TestEnum> clone = cloner.deepClone(m); assertSame(clone.get(1), TestEnum.A); assertSame(clone.get(2), TestEnum.B); assertSame(clone.get(3), TestEnum.C); } public void testCustomAnnotation() { final Cloner cloner = new Cloner() { @Override protected Class<?> getImmutableAnnotation() { return MyImmutable.class; } }; final MyAX o = new MyAX(); final MyAX c = cloner.deepClone(o); assertSame(o, c); } public void testConsiderImmutable() { final Cloner cloner = new Cloner() { @Override protected boolean considerImmutable(final Class<?> clz) { return clz == Object.class; } }; final Object o = new Object(); final Object c = cloner.deepClone(o); assertSame(o, c); } class X { private X(int x) { x = 5; } } @Immutable(subClass = true) static public class ATestImmutable { } static public class ATestImmutableSubclass extends ATestImmutable { } @Immutable static public class BTestImmutable { } static public class BTestImmutableSubclass extends BTestImmutable { } public void testIssue7() { final HashMap<Object, Object> source = new HashMap<Object, Object>(); source.put("string", "string"); source.put("array", new Integer[]{1, 2, 3}); final HashMap<Object, Object> sc = cloner.shallowClone(source); assertEquals("string", sc.get("string")); } public void testIgnoreInstanceOf() { final Cloner cloner = new Cloner(); cloner.dontCloneInstanceOf(A.class); final A a = new A() { }; assertNotSame(a.getClass(), A.class); assertSame(a, cloner.deepClone(a)); } public void testImmutableSubclassNotEnabled() { final BTestImmutableSubclass a = new BTestImmutableSubclass(); final BTestImmutableSubclass ca = cloner.deepClone(a); assertNotSame(a, ca); } public void testImmutableSubclass() { final ATestImmutableSubclass a = new ATestImmutableSubclass(); assertSame(a, cloner.deepClone(a)); assertSame(a, cloner.deepClone(a)); } public void testImmutable() { final ATestImmutable a = new ATestImmutable(); assertSame(a, cloner.deepClone(a)); assertSame(a, cloner.deepClone(a)); } /** * tests if it happens that in the deep-graph of the cloned objects, * if a reference to the same object exists twice, the cloned object * will have only 1 clone and references to this clone. */ public void testCloningOfSameObject() { final Object o1 = new Object(); final Object o2 = new Object(); class OO { Object o1, o2, o3, o4; } final OO oo = new OO(); oo.o1 = o1; oo.o2 = o2; oo.o3 = o1; oo.o4 = o2; OO clone = cloner.deepClone(oo); assertTrue(clone.o1 == clone.o3); assertTrue(clone.o2 == clone.o4); final HashSet<Object> h1 = new HashSet<Object>(); final HashSet<Object> h2 = new HashSet<Object>(); oo.o1 = h1; oo.o2 = h2; oo.o3 = h1; oo.o4 = h2; clone = cloner.deepClone(oo); assertTrue(clone.o1 == clone.o3); assertTrue(clone.o2 == clone.o4); assertTrue(clone.o1 != clone.o2); assertTrue(clone.o2 != clone.o3); } /** * tests if immutable clone is the same instance */ public void testCloneImmutables() { final String s = "test1"; final String clone1 = cloner.deepClone(s); assertSame(s, clone1); } /** * tests if immutable clone is the same instance */ public void testCloneFloat() { final Float float1 = new Float(8); final Float cloned = cloner.deepClone(float1); assertSame(float1, cloned); assertEquals(float1, cloned); } /** * tests if arrays are cloned correctly */ public void testCloneArrays() { final int[] ia = {1, 2, 3}; final int[] cloned = cloner.deepClone(ia); assertEquals(ia.length, cloned.length); for (int i = 0; i < ia.length; i++) { assertEquals(ia[i], cloned[i]); } final double[] da = {1, 2, 3}; final double[] dcloned = cloner.deepClone(da); assertEquals(da.length, dcloned.length); for (int i = 0; i < ia.length; i++) { assertEquals(da[i], dcloned[i]); } } private class Simple { private int x = 1; private String s = "simple"; private Complex complex; public Complex getComplex() { return complex; } public void setComplex(final Complex complex) { this.complex = complex; } public int getX() { return x; } public void setX(final int x) { this.x = x; } public String getS() { return s; } public void setS(final String s) { this.s = s; } @Override public boolean equals(final Object obj) { if (obj instanceof Simple) { final Simple s = (Simple) obj; return s.getS().equals(getS()) && s.getX() == getX(); } return super.equals(obj); } } /** * tests cloning of a simple class */ public void testCloneSimple() { final Simple simple = new Simple(); simple.setS("x1"); simple.setX(20); final Simple clone = cloner.deepClone(simple); assertEquals(simple.getS(), clone.getS()); assertSame(simple.getS(), clone.getS()); assertEquals(simple.getX(), clone.getX()); simple.setS("x2"); simple.setX(30); assertNotSame(simple.getS(), clone.getS()); assertFalse(simple.getS().equals(clone.getS())); assertFalse(simple.getX() == clone.getX()); } protected class Complex { private int x = 1; private String s = "complex"; private final List<Simple> l = new ArrayList<Simple>(); public Complex() { l.add(new Simple()); final Simple simple = new Simple(); simple.setS("s2"); simple.setX(30); l.add(simple); simple.setComplex(this); } public int getX() { return x; } public void setX(final int x) { this.x = x; } public String getS() { return s; } public List<Simple> getL() { return l; } public void setS(final String s) { this.s = s; } } /** * test cloning of a complex object graph */ public void testCloneComplex() { final Complex complex = new Complex(); complex.setS("x1"); complex.setX(20); final Complex clone = cloner.deepClone(complex); assertEquals(complex.getS(), clone.getS()); assertEquals(complex.getX(), clone.getX()); assertEquals(complex.getL().size(), clone.getL().size()); final Simple simple1 = complex.getL().get(0); final Simple simple2 = complex.getL().get(1); final Simple simple1Clone = clone.getL().get(0); final Simple simple2Clone = clone.getL().get(1); assertNotSame(simple1, simple1Clone); assertNotSame(simple2, simple2Clone); assertEquals(simple1, simple1Clone); assertEquals(simple2, simple2Clone); } public void testShallowClone() { final Simple simple1 = new Simple(); final Complex complex = new Complex(); simple1.setComplex(complex); simple1.setX(5); simple1.setS("test"); final Simple shallowClone = cloner.shallowClone(simple1); assertNotSame(simple1, shallowClone); assertSame(simple1.getComplex(), shallowClone.getComplex()); assertEquals(simple1.getX(), shallowClone.getX()); assertEquals(simple1.getS(), shallowClone.getS()); shallowClone.setX(10); assertTrue(shallowClone.getX() != simple1.getX()); shallowClone.setS("x"); assertTrue(shallowClone.getS() != simple1.getS()); } public void testCloneStack() { final List<Integer> lst = new LinkedList<Integer>(); for (int i = 0; i < 100000; i++) { lst.add(i); } final List<Integer> clone = cloner.deepClone(lst); assertEquals(lst.size(), clone.size()); } public void testCloneTreeSet() { final TreeSet<DC> set = new TreeSet<DC>(); final DC dc1 = new DC(5); set.add(dc1); final DC dc2 = new DC(10); set.add(dc2); assertTrue(set.contains(dc1)); assertTrue(set.contains(dc2)); assertTrue(set.remove(dc1)); set.add(dc1); // cloner.setDumpClonedClasses(true); final TreeSet<DC> set2 = cloner.deepClone(set); assertTrue(set2.contains(dc1)); assertTrue(set2.contains(dc2)); assertTrue(set2.remove(dc1)); assertEquals(1, set2.size()); } public void testCloneHashSet() { Set<DC> set = new HashSet<DC>(); final DC dc1 = new DC(5); set.add(dc1); final DC dc2 = new DC(10); set.add(dc2); assertTrue(set.contains(dc1)); assertTrue(set.contains(dc2)); assertTrue(set.remove(dc1)); set.add(dc1); // cloner.setDumpClonedClasses(true); set = cloner.deepClone(set); assertTrue(set.contains(dc1)); assertTrue(set.contains(dc2)); assertTrue(set.remove(dc1)); assertEquals(1, set.size()); } public void testCloneStability() { for (int i = 0; i < 10; i++) { final Complex complex = new Complex(); complex.setS("x1"); complex.setX(20); final ArrayList<Object> l = new ArrayList<Object>(); l.add(complex); final HashSet<Object> h1 = new HashSet<Object>(); final HashSet<Object> h2 = new HashSet<Object>(); for (int j = 0; j < 100; j++) { h1.add(j); h2.add("string" + j); h1.add(Calendar.getInstance()); h2.add(new Date()); l.add(new Random()); } l.add(h1); l.add(h2); final Complex clone = cloner.deepClone(complex); l.add(clone); cloner.deepClone(l); } } public void testArrayListCloning() { final ArrayList<Object> l = new ArrayList<Object>(); l.add(Calendar.getInstance()); l.add(2); l.add(3); l.add("kostas"); final ArrayList<Object> cloned = cloner.deepClone(l); assertEquals(l.size(), cloned.size()); for (int i = 0; i < l.size(); i++) { assertEquals(l.get(i), cloned.get(i)); } assertNotSame(l, cloned); assertNotSame(l.get(0), cloned.get(0)); assertSame(l.get(1), cloned.get(1)); l.add(5); assertEquals(4, cloned.size()); cloned.add(8); assertEquals(5, l.size()); } public void testLinkedListCloning() { final LinkedList<Object> l = new LinkedList<Object>(); l.add(Calendar.getInstance()); l.add(2); l.add(3); l.add("kostas"); final LinkedList<Object> cloned = cloner.deepClone(l); assertEquals(l.size(), cloned.size()); for (int i = 0; i < l.size(); i++) { assertEquals(l.get(i), cloned.get(i)); } assertNotSame(l, cloned); assertNotSame(l.get(0), cloned.get(0)); assertSame(l.get(1), cloned.get(1)); l.add(5); assertEquals(4, cloned.size()); cloned.add(8); assertEquals(5, l.size()); } public void testHashSetCloning() { final HashSet<Object> l = new HashSet<Object>(); l.add(Calendar.getInstance()); l.add(2); l.add(3); l.add("kostas"); final HashSet<Object> cloned = cloner.deepClone(l); assertNotSame(l, cloned); assertEquals(l.size(), cloned.size()); for (final Object o : l) { assertTrue(cloned.contains(o)); } } public void testHashMapCloning() { final HashMap<String, Object> m = new HashMap<String, Object>(); m.put("kostas", Calendar.getInstance()); m.put("tina", 500); m.put("george", "Ah!"); final HashMap<String, Object> cloned = cloner.deepClone(m); assertEquals(m.size(), cloned.size()); for (final Map.Entry<String, Object> e : m.entrySet()) { assertEquals(e.getValue(), cloned.get(e.getKey())); } assertNotSame(m, cloned); assertNotSame(m.get("kostas"), cloned.get("kostas")); assertSame(m.get("tina"), cloned.get("tina")); cloned.put("x", 100); assertEquals(3, m.size()); assertEquals(4, cloned.size()); } public void testTreeMapCloning() { final TreeMap<String, Object> m = new TreeMap<String, Object>(); m.put("kostas", Calendar.getInstance()); m.put("tina", 500); m.put("george", "Ah!"); final TreeMap<String, Object> cloned = cloner.deepClone(m); assertEquals(m.size(), cloned.size()); for (final Map.Entry<String, Object> e : m.entrySet()) { assertEquals(e.getValue(), cloned.get(e.getKey())); } assertNotSame(m, cloned); assertNotSame(m.get("kostas"), cloned.get("kostas")); assertSame(m.get("tina"), cloned.get("tina")); cloned.put("x", 100); assertEquals(3, m.size()); assertEquals(4, cloned.size()); } public void testTransientNullPositive() { final Cloner c = new Cloner(); c.setNullTransient(true); final TransientTest tt = new TransientTest(); final TransientTest deepClone = c.deepClone(tt); assertNull(deepClone.tr1); assertNull(deepClone.a); assertEquals(0, deepClone.i); assertNotNull(deepClone.nontr); } public void testTransientNullNegative() { final Cloner c = new Cloner(); c.setNullTransient(false); final TransientTest tt = new TransientTest(); final TransientTest deepClone = c.deepClone(tt); assertNotNull(deepClone.tr1); assertNotNull(deepClone.a); assertNotNull(deepClone.nontr); } public void testCopyPropertiesArrayPrimitive() { final int[] src = new int[]{5, 6, 7}; final int[] dest = new int[3]; cloner.copyPropertiesOfInheritedClass(src, dest); assertEquals(src[0], dest[0]); assertEquals(src[1], dest[1]); assertEquals(src[2], dest[2]); } public void testCopyPropertiesArray() { final Object[] src = new Object[]{new Integer(5), new Float(8.5f), new Double(3.5d)}; final Object[] dest = new Object[3]; cloner.copyPropertiesOfInheritedClass(src, dest); assertEquals(src[0], dest[0]); assertEquals(src[1], dest[1]); assertEquals(src[2], dest[2]); } public void testCopyPropertiesInheritedClasses() { final A a = new A(); final B b = new B(); b.setName("x"); b.setX(-1); b.setY(10); cloner.copyPropertiesOfInheritedClass(a, b); assertEquals("kostas", b.getName()); assertEquals(5, b.getX()); assertEquals(10, b.getY()); } public void testFreezable() { final F f = new F(); assertNotSame(f, cloner.deepClone(f)); f.setFrozen(true); assertSame(f, cloner.deepClone(f)); } public void testDeepCloneDontCloneInstances() { final A a = new A(); final B b = new B(); final G g = new G(a, b); final G cga = cloner.deepCloneDontCloneInstances(g, a); assertNotSame(g, cga); assertNotSame(cga.getB(), b); assertSame(cga.getA(), a); final G cgab = cloner.deepCloneDontCloneInstances(g, a, b); assertNotSame(g, cgab); assertSame(cgab.getB(), b); assertSame(cgab.getA(), a); } static class SynthOuter { public Inner getInner() { return new Inner(); } class Inner { Object x = new Object(); public SynthOuter getOuter() { return SynthOuter.this; } } } public void testDontCloneSynthetic() { final Cloner cloner = new Cloner(); cloner.setCloneSynthetics(false); final SynthOuter outer = new SynthOuter(); final Inner inner = outer.getInner(); final Inner clonedInner = cloner.deepClone(inner); assertNotSame(inner, clonedInner); assertNotSame(inner.x, clonedInner.x); assertSame(outer, clonedInner.getOuter()); } public void testTreeMapWithComparator() { final TreeMap<Object, String> m = new TreeMap<Object, String>(new Comparator<Object>() { public int compare(final Object o1, final Object o2) { return o1.hashCode() - o2.hashCode(); } }); m.put(new Object() { @Override public int hashCode() { return 1; } }, "1"); m.put(new Object() { @Override public int hashCode() { return 2; } }, "2"); final TreeMap<Object, String> clone = cloner.deepClone(m); assertEquals(m, clone); } public void testTreeSetWithComparator() { final TreeSet<Object> set = new TreeSet<Object>(new Comparator<Object>() { public int compare(final Object o1, final Object o2) { return o1.hashCode() - o2.hashCode(); } }); set.add(new Object() { @Override public int hashCode() { return 1; } }); set.add(new Object() { @Override public int hashCode() { return 2; } }); final TreeSet<Object> clone = cloner.deepClone(set); assertEquals(set, clone); } public void testEnumIssue9() { final TestEnum original = TestEnum.A; final TestEnum clone = cloner.deepClone(original); assertSame(clone, original); } public void testDate() { Date original = new Date(); Cloner cloner = new Cloner(); cloner.setNullTransient(true); Date clone = cloner.deepClone(original); // I expect this to be true, but is is false. assertEquals(0, clone.getTime()); } public void testUnregisterFastCloner() { Cloner cloner = new Cloner(); cloner.unregisterFastCloner(HashMap.class); cloner.registerFastCloner(HashMap.class, new FastClonerHashMap()); } public void testEmptyLinkedHashMap() { LinkedHashMap<Integer, Integer> m = new LinkedHashMap<Integer, Integer>(); LinkedHashMap<Integer, Integer> cloned = cloner.deepClone(m); assertEquals(m, cloned); } public void testLinkedHashMap() { LinkedHashMap<Integer, Integer> m = new LinkedHashMap<Integer, Integer>(); for (int i = 1; i < 10000; i++) { m.put(i, i * 2); } LinkedHashMap<Integer, Integer> cloned = cloner.deepClone(m); assertEquals(m, cloned); } public void testLinkedHashMapIterationOrder() { LinkedHashMap<Integer, Integer> m = new LinkedHashMap<Integer, Integer>(); for (int i = 1000; i >= 1; i--) { m.put(i, i * 2); } LinkedHashMap<Integer, Integer> cloned = cloner.deepClone(m); Iterator<Integer> it = cloned.keySet().iterator(); for (int i = 1000; i >= 1; i--) { assertEquals((Integer) i, it.next()); } } }