package org.jadira.cloning;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.LinkedList;
import java.util.List;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import org.jadira.cloning.data.DeepCopyHolder;
import org.jadira.cloning.data.ExampleEnum;
import org.jadira.cloning.data.IdHolder;
import org.jadira.cloning.data.ReferencesHolder;
import org.jadira.reflection.access.unsafe.UnsafeOperations;
import org.jadira.reflection.cloning.BasicCloner;
import org.jadira.reflection.cloning.MinimalCloner;
import org.jadira.reflection.cloning.api.Cloner;
import org.jadira.reflection.cloning.implementor.AsmCloneStrategy;
import org.jadira.reflection.cloning.implementor.InvokeDynamicCloneStrategy;
import org.jadira.reflection.cloning.implementor.PortableCloneStrategy;
import org.junit.Assert;
import org.junit.Test;
public class TestCloner {
private static final Cloner[] CLONERS = new Cloner[] { new BasicCloner(), new BasicCloner(new InvokeDynamicCloneStrategy()), new BasicCloner(new AsmCloneStrategy()), new BasicCloner(new PortableCloneStrategy()), new MinimalCloner() };
/**
* Test that verifies that JDK types are handled correctly
*/
@Test
public void testImmutableType() {
for (int i = 0; i < CLONERS.length; i++) {
doTestImmutableType(CLONERS[i]);
}
}
public void doTestImmutableType(Cloner cloner) {
final Double double1 = 1203.23D;
final Double clonedDouble1 = cloner.clone(double1);
assertSame(double1, clonedDouble1);
assertEquals(double1, clonedDouble1);
final String string1 = "TESTDATA_STRING";
final String clonedString = cloner.clone(string1);
assertSame(string1, clonedString);
assertEquals(string1, clonedString);
}
/**
* Test that ensures references are properly preserved during a clone
*/
@Test
public void testReferencesWiring() {
for (int i = 0; i < CLONERS.length; i++) {
doTestReferencesWiring(CLONERS[i]);
}
}
public void doTestReferencesWiring(Cloner cloner) {
final Object ref1 = new Object();
final Object ref2 = new Object();
final ReferencesHolder refHolder = new ReferencesHolder();
refHolder.ref1 = ref1;
refHolder.ref2 = ref2;
refHolder.ref3 = ref1;
refHolder.ref4 = ref2;
ReferencesHolder refHolderClone = cloner.clone(refHolder);
assertSame(refHolder.ref1, refHolder.ref3);
assertSame(refHolder.ref2, refHolder.ref4);
assertNotSame(refHolder.ref1, refHolder.ref2);
assertNotSame(refHolder.ref2, refHolder.ref3);
assertSame(refHolderClone.ref1, refHolderClone.ref3);
assertSame(refHolderClone.ref2, refHolderClone.ref4);
assertNotSame(refHolderClone.ref1, refHolderClone.ref2);
assertNotSame(refHolderClone.ref2, refHolderClone.ref3);
}
@Test
public void testDate() {
for (int i = 0; i < CLONERS.length; i++) {
if (CLONERS[i] instanceof BasicCloner) {
doTestDate((BasicCloner)CLONERS[i]);
} else {
doTestDate((MinimalCloner)CLONERS[i]);
}
}
}
public void doTestDate(BasicCloner cloner) {
Date original = new Date();
cloner.setCloneTransientFields(false);
Date clone = cloner.clone(original);
assertEquals(0, clone.getTime());
cloner.setCloneTransientFields(true);
clone = cloner.clone(original);
assertEquals(original.getTime(), clone.getTime());
}
public void doTestDate(MinimalCloner cloner) {
// MinimalCloner doesn't offer the capability to ignore transients
// so we don't test for that
Date original = new Date();
Date clone = cloner.clone(original);
assertEquals(original.getTime(), clone.getTime());
}
@Test
public void testEnum() {
for (int i = 0; i < CLONERS.length; i++) {
doTestEnum(CLONERS[i]);
}
}
public void doTestEnum(Cloner cloner) {
final ExampleEnum original = ExampleEnum.A;
assertTrue(original.getClass().isEnum());
final ExampleEnum clone = cloner.clone(original);
assertSame(clone, original);
}
@Test
public void testArray() {
for (int i = 0; i < CLONERS.length; i++) {
doTestArray(CLONERS[i]);
}
}
public void doTestArray(Cloner cloner) {
final String[] stringArray = { "TEST", "CLONING", "ARRAY" };
final String[] stringArrayClone = cloner.clone(stringArray);
assertEquals(stringArray.length, stringArrayClone.length);
for (int i = 0; i < stringArray.length; i++) {
assertEquals(stringArray[i], stringArrayClone[i]);
}
final double[] doubleArray = { 1.01, 2.3234, 3.234321 };
final double[] doubleArrayClone = cloner.clone(doubleArray);
assertEquals(doubleArray.length, doubleArrayClone.length);
for (int i = 0; i < doubleArray.length; i++) {
assertEquals(doubleArray[i], doubleArrayClone[i], 0.00000000001);
}
}
@Test
public void testLargeLinkedList() {
for (int i = 0; i < CLONERS.length; i++) {
doTestLargeLinkedList(CLONERS[i]);
}
}
public void doTestLargeLinkedList(Cloner cloner) {
final List<Integer> lst = new LinkedList<Integer>();
for (int i = 0; i < 100000; i++) {
lst.add(i);
}
final List<Integer> clone = cloner.clone(lst);
assertEquals(lst.size(), clone.size());
}
@Test
public void testLinkedList() {
for (int i = 0; i < CLONERS.length - 1; i++) {
doTestLinkedList(CLONERS[i]);
}
}
public void doTestLinkedList(Cloner cloner) {
final LinkedList<Object> linkedList = new LinkedList<Object>();
linkedList.add(100D);
linkedList.add("This is a String");
linkedList.add(35);
linkedList.add(42);
final LinkedList<Object> clonedLinkedList = cloner.clone(linkedList);
assertEquals(linkedList.size(), clonedLinkedList.size());
for (int i = 0; i < linkedList.size(); i++) {
assertEquals(linkedList.get(i), clonedLinkedList.get(i));
}
assertNotSame(linkedList, clonedLinkedList);
assertSame(linkedList.get(0), clonedLinkedList.get(0));
assertEquals(linkedList.get(0), clonedLinkedList.get(0));
assertEquals(4, linkedList.size());
linkedList.add(77);
assertEquals(5, linkedList.size());
assertEquals(4, clonedLinkedList.size());
clonedLinkedList.add(8);
assertEquals(5, clonedLinkedList.size());
}
@Test
public void testBasicWithPortable() throws DatatypeConfigurationException {
GregorianCalendar cal = new GregorianCalendar();
cal.add(Calendar.YEAR, 10);
XMLGregorianCalendar xmlCal = DatatypeFactory.newInstance().newXMLGregorianCalendar((GregorianCalendar) cal);
cal.add(Calendar.MONTH, 3);
DeepCopyHolder source = new DeepCopyHolder();
source.value = new IdHolder();
source.value.setId("A Sample Value to Copy");
source.timestamp = new Timestamp(System.currentTimeMillis() + 10000000);
source.calendar = cal;
source.xmlCalendar = xmlCal;
BasicCloner cloner = new BasicCloner(new PortableCloneStrategy());
cloner.initialiseFor(IdHolder.class);
DeepCopyHolder dest = cloner.clone(source);
Assert.assertEquals(source.value, dest.value);
Assert.assertNotSame(source.value, dest.value);
Assert.assertEquals(source.timestamp, dest.timestamp);
Assert.assertNotSame(source.timestamp, dest.timestamp);
Assert.assertEquals(source.calendar, dest.calendar);
Assert.assertNotSame(source.calendar, dest.calendar);
Assert.assertEquals(source.xmlCalendar, dest.xmlCalendar);
Assert.assertNotSame(source.xmlCalendar, dest.xmlCalendar);
}
@Test
public void testUnsafeOperations() throws DatatypeConfigurationException {
GregorianCalendar cal = new GregorianCalendar();
cal.add(Calendar.YEAR, 10);
XMLGregorianCalendar xmlCal = DatatypeFactory.newInstance().newXMLGregorianCalendar((GregorianCalendar) cal);
cal.add(Calendar.MONTH, 3);
DeepCopyHolder source = new DeepCopyHolder();
source.value = new IdHolder();
source.value.setId("A Sample Value to Copy");
source.timestamp = new Timestamp(System.currentTimeMillis() + 10000000);
source.calendar = cal;
source.xmlCalendar = xmlCal;
DeepCopyHolder dest = UnsafeOperations.getUnsafeOperations().deepCopy(source);
Assert.assertEquals(source.value, dest.value);
Assert.assertNotSame(source.value, dest.value);
Assert.assertEquals(source.timestamp, dest.timestamp);
Assert.assertNotSame(source.timestamp, dest.timestamp);
Assert.assertEquals(source.calendar, dest.calendar);
Assert.assertNotSame(source.calendar, dest.calendar);
Assert.assertEquals(source.xmlCalendar, dest.xmlCalendar);
Assert.assertNotSame(source.xmlCalendar, dest.xmlCalendar);
}
@Test
public void testMinimal() throws DatatypeConfigurationException {
GregorianCalendar cal = new GregorianCalendar();
cal.add(Calendar.YEAR, 10);
XMLGregorianCalendar xmlCal = DatatypeFactory.newInstance().newXMLGregorianCalendar((GregorianCalendar) cal);
cal.add(Calendar.MONTH, 3);
DeepCopyHolder source = new DeepCopyHolder();
source.value = new IdHolder();
source.value.setId("A Sample Value to Copy");
source.timestamp = new Timestamp(System.currentTimeMillis() + 10000000);
source.calendar = cal;
source.xmlCalendar = xmlCal;
MinimalCloner mcloner = new MinimalCloner();
DeepCopyHolder dest = mcloner.clone(source);
Assert.assertEquals(source.value, dest.value);
Assert.assertNotSame(source.value, dest.value);
Assert.assertEquals(source.timestamp, dest.timestamp);
Assert.assertNotSame(source.timestamp, dest.timestamp);
Assert.assertEquals(source.calendar, dest.calendar);
Assert.assertNotSame(source.calendar, dest.calendar);
Assert.assertEquals(source.xmlCalendar, dest.xmlCalendar);
Assert.assertNotSame(source.xmlCalendar, dest.xmlCalendar);
}
public void testBasic() throws DatatypeConfigurationException {
GregorianCalendar cal = new GregorianCalendar();
cal.add(Calendar.YEAR, 10);
XMLGregorianCalendar xmlCal = DatatypeFactory.newInstance().newXMLGregorianCalendar((GregorianCalendar) cal);
cal.add(Calendar.MONTH, 3);
DeepCopyHolder source = new DeepCopyHolder();
source.value = new IdHolder();
source.value.setId("A Sample Value to Copy");
source.timestamp = new Timestamp(System.currentTimeMillis() + 10000000);
source.calendar = cal;
source.xmlCalendar = xmlCal;
BasicCloner cloner = new BasicCloner();
cloner.initialiseFor(IdHolder.class);
DeepCopyHolder dest = cloner.clone(source);
Assert.assertEquals(source.value, dest.value);
Assert.assertNotSame(source.value, dest.value);
Assert.assertEquals(source.timestamp, dest.timestamp);
Assert.assertNotSame(source.timestamp, dest.timestamp);
Assert.assertEquals(source.calendar, dest.calendar);
Assert.assertNotSame(source.calendar, dest.calendar);
Assert.assertEquals(source.xmlCalendar, dest.xmlCalendar);
Assert.assertNotSame(source.xmlCalendar, dest.xmlCalendar);
}
}