/*******************************************************************************
* Copyright (c) 2006-2013 The RCP Company and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* The RCP Company - initial API and implementation
*******************************************************************************/
package com.rcpcompany.uibindings.model.utils.tests;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.EContentAdapter;
import org.junit.Before;
import org.junit.Test;
import com.rcpcompany.test.utils.EMFTestUtils;
import com.rcpcompany.uibindings.moao.IMOAOPackage;
import com.rcpcompany.uibindings.model.utils.BasicUtils;
import com.rcpcompany.uibindings.model.utils.EcoreExtendedUtils;
import com.rcpcompany.uibindings.model.utils.EcoreExtendedUtils.SyncController;
import com.rcpcompany.uibindings.tests.shop.Contact;
import com.rcpcompany.uibindings.tests.shop.Country;
import com.rcpcompany.uibindings.tests.shop.Shop;
import com.rcpcompany.uibindings.tests.shop.ShopFactory;
import com.rcpcompany.uibindings.tests.shop.ShopItem;
import com.rcpcompany.uibindings.tests.shop.ShopPackage;
/**
* Tests of {@link EcoreExtUtils#sync(EObject, EObject)} and friends.
*
* @author Tonny Madsen, The RCP Company
*
*/
public class EcoreExtendedUtilsSyncTest {
/**
* Check a few constraints on the model is correct
*/
@Before
public void modelRequirements() {
final EReference ref = ShopPackage.Literals.SHOP__SHOP_ITEMS;
assertNotNull(ref);
final List<EAttribute> keys = ref.getEKeys();
assertNotNull(keys);
assertEquals(1, keys.size());
assertEquals("name", keys.get(0).getName());
}
/**
* Test sync of a single attribute
*/
@Test
public void testAttributeSync() {
final Country source = ShopFactory.eINSTANCE.createCountry();
source.setName("abc");
source.setAbbreviation("AB");
final Country target = ShopFactory.eINSTANCE.createCountry();
target.setName("cba");
target.setAbbreviation("AB");
sync(target, source, null, IMOAOPackage.Literals.NAMED_OBJECT__NAME);
assertEquals("abc", target.getName());
assertEquals("AB", target.getAbbreviation());
}
/**
* Test sync of a reference
*/
@Test
public void testReferenceSync() {
final Contact source = ShopFactory.eINSTANCE.createContact();
source.setName("Tonny");
final Country sourceCountry = ShopFactory.eINSTANCE.createCountry();
sourceCountry.setName("abc");
sourceCountry.setAbbreviation("AB");
source.setCountry(sourceCountry);
final Contact target = ShopFactory.eINSTANCE.createContact();
target.setName("Allan");
final Country targetCountry = ShopFactory.eINSTANCE.createCountry();
targetCountry.setName("cba");
targetCountry.setAbbreviation("AB");
target.setCountry(targetCountry);
sync(target, source, null, IMOAOPackage.Literals.NAMED_OBJECT__NAME, ShopPackage.Literals.CONTACT__COUNTRY,
ShopPackage.Literals.CONTACT__COUNTRY); // Country: s -> null ->
// t
assertEquals("Tonny", target.getName());
assertEquals("cba", targetCountry.getName());// NOT CHANGED! Not
// containment
assertEquals("AB", targetCountry.getAbbreviation());
}
/**
* Test sync of many-attribute
*/
@Test
public void testManyAttributeSync1() {
final ShopItem source = ShopFactory.eINSTANCE.createShopItem();
source.setName("abc");
source.getLocations().add("a");
source.getLocations().add("b");
final ShopItem target = ShopFactory.eINSTANCE.createShopItem();
target.setName("abc");
sync(target, source, null, ShopPackage.Literals.SHOP_ITEM__LOCATIONS, ShopPackage.Literals.SHOP_ITEM__LOCATIONS);
assertEquals("abc", target.getName());
assertEquals(2, target.getLocations().size());
assertEquals("a", target.getLocations().get(0));
assertEquals("b", target.getLocations().get(1));
}
/**
* Test sync of many-attribute
*/
@Test
public void testManyAttributeSync2() {
final ShopItem source = ShopFactory.eINSTANCE.createShopItem();
source.setName("abc");
source.getLocations().add("b");
source.getLocations().add("q");
final ShopItem target = ShopFactory.eINSTANCE.createShopItem();
target.setName("abc");
target.getLocations().add("b");
target.getLocations().add("c");
sync(target, source, null, ShopPackage.Literals.SHOP_ITEM__LOCATIONS);
assertEquals("abc", target.getName());
assertEquals(2, target.getLocations().size());
assertEquals("b", target.getLocations().get(0));
assertEquals("q", target.getLocations().get(1));
}
/**
* Test sync of many-attribute
*/
@Test
public void testManyAttributeSync3() {
final ShopItem source = ShopFactory.eINSTANCE.createShopItem();
source.setName("abc");
source.getLocations().add("d");
source.getLocations().add("a");
source.getLocations().add("b");
source.getLocations().add("q");
final ShopItem target = ShopFactory.eINSTANCE.createShopItem();
target.setName("abc");
target.getLocations().add("a");
target.getLocations().add("b");
target.getLocations().add("c");
sync(target, source, null, ShopPackage.Literals.SHOP_ITEM__LOCATIONS, ShopPackage.Literals.SHOP_ITEM__LOCATIONS);
assertEquals("abc", target.getName());
assertEquals(4, target.getLocations().size());
assertEquals("d", target.getLocations().get(0));
assertEquals("a", target.getLocations().get(1));
assertEquals("b", target.getLocations().get(2));
assertEquals("q", target.getLocations().get(3));
}
/**
* Test sync of many-attribute
*/
@Test
public void testManyAttributeSync4() {
final ShopItem source = ShopFactory.eINSTANCE.createShopItem();
source.setName("abc");
source.getLocations().add("c");
source.getLocations().add("d");
final ShopItem target = ShopFactory.eINSTANCE.createShopItem();
target.setName("abc");
target.getLocations().add("a");
target.getLocations().add("b");
target.getLocations().add("c");
target.getLocations().add("d");
sync(target, source, null, ShopPackage.Literals.SHOP_ITEM__LOCATIONS, ShopPackage.Literals.SHOP_ITEM__LOCATIONS);
assertEquals("abc", target.getName());
assertEquals(2, target.getLocations().size());
assertEquals("c", target.getLocations().get(0));
assertEquals("d", target.getLocations().get(1));
}
/**
* Test sync of containment reference
*/
@Test
public void testContainmentSync() {
final Shop source = ShopFactory.eINSTANCE.createShop();
final ShopItem shopItem1 = ShopFactory.eINSTANCE.createShopItem();
shopItem1.setName("1");
shopItem1.setPrice(100f);
shopItem1.setShop(source);
final ShopItem shopItem2a = ShopFactory.eINSTANCE.createShopItem();
shopItem2a.setName("2");
shopItem2a.setPrice(100f);
shopItem2a.setShop(source);
final Shop target = ShopFactory.eINSTANCE.createShop();
final ShopItem shopItem2b = ShopFactory.eINSTANCE.createShopItem();
shopItem2b.setName("2");
shopItem2b.setPrice(200f);
shopItem2b.setShop(target);
sync(target, source, null, ShopPackage.Literals.SHOP_ITEM__PRICE, ShopPackage.Literals.SHOP__SHOP_ITEMS);
assertEquals(2, target.getShopItems().size());
assertEquals(target, shopItem1.getShop());
assertEquals(target, shopItem2b.getShop());
assertEquals(100f, shopItem2b.getPrice(), 0.001f);
}
/**
* Test sync of mixed containment/non-containment references.
* <p>
* contact1 is new and moved to target. BUT the country of the contact (reference) must be updated to country2
*/
@Test
public void testContainmentMixedSync() {
final Shop source = ShopFactory.eINSTANCE.createShop();
final Country country1 = ShopFactory.eINSTANCE.createCountry();
country1.setAbbreviation("DK");
country1.setName("Denmark");
country1.setShop(source);
final Contact contact1 = ShopFactory.eINSTANCE.createContact();
contact1.setName("Tonny");
contact1.setCountry(country1);
contact1.setShop(source);
final Shop target = ShopFactory.eINSTANCE.createShop();
final Country country2 = ShopFactory.eINSTANCE.createCountry();
country2.setAbbreviation("DK");
country2.setName("Danmark");
country2.setShop(target);
sync(target, source, null, IMOAOPackage.Literals.NAMED_OBJECT__NAME, ShopPackage.Literals.SHOP__CONTACTS,
ShopPackage.Literals.CONTACT__COUNTRY, ShopPackage.Literals.COUNTRY__CONTACTS);
assertEquals(1, target.getCountries().size());
assertEquals(1, target.getContacts().size());
assertEquals(target, country2.getShop());
assertEquals(target, contact1.getShop());
assertEquals(country2, contact1.getCountry());
assertEquals("Denmark", country2.getName());
}
/**
* Test sync of containment reference
*/
@Test
public void testContainmentListSync1() {
final Shop source = ShopFactory.eINSTANCE.createShop();
final ShopItem shopItem1 = ShopFactory.eINSTANCE.createShopItem();
shopItem1.setName("1");
shopItem1.setPrice(100f);
shopItem1.setShop(source);
final ShopItem shopItem2a = ShopFactory.eINSTANCE.createShopItem();
shopItem2a.setName("2");
shopItem2a.setPrice(100f);
shopItem2a.setShop(source);
final Shop target = ShopFactory.eINSTANCE.createShop();
final ShopItem shopItem2b = ShopFactory.eINSTANCE.createShopItem();
shopItem2b.setName("2");
shopItem2b.setPrice(200f);
shopItem2b.setShop(target);
sync(target, target.getShopItems(), source.getShopItems(), null, ShopPackage.Literals.SHOP_ITEM__PRICE,
ShopPackage.Literals.SHOP__SHOP_ITEMS);
assertEquals(2, target.getShopItems().size());
assertEquals(target, shopItem1.getShop());
assertEquals(target, shopItem2b.getShop());
assertEquals(100f, shopItem2b.getPrice(), 0.001f);
}
/**
* Test sync of containment reference
*/
@Test
public void testContainmentListSync2() {
final EList<ShopItem> sourceList = new BasicEList<ShopItem>();
final ShopItem shopItem1 = ShopFactory.eINSTANCE.createShopItem();
shopItem1.setName("1");
shopItem1.setPrice(100f);
sourceList.add(shopItem1);
final ShopItem shopItem2a = ShopFactory.eINSTANCE.createShopItem();
shopItem2a.setName("2");
shopItem2a.setPrice(100f);
sourceList.add(shopItem2a);
final Shop target = ShopFactory.eINSTANCE.createShop();
final ShopItem shopItem2b = ShopFactory.eINSTANCE.createShopItem();
shopItem2b.setName("2");
shopItem2b.setPrice(200f);
shopItem2b.setShop(target);
final ShopItem shopItem3 = ShopFactory.eINSTANCE.createShopItem();
shopItem3.setName("3");
shopItem3.setPrice(300f);
shopItem3.setShop(target);
sync(target, target.getShopItems(), sourceList, new EObject[] { shopItem3 },
ShopPackage.Literals.SHOP_ITEM__PRICE, ShopPackage.Literals.SHOP__SHOP_ITEMS,
ShopPackage.Literals.SHOP_ITEM__SHOP, ShopPackage.Literals.SHOP__SHOP_ITEMS);
assertEquals(2, target.getShopItems().size());
assertEquals(target, shopItem1.getShop());
assertEquals(target, shopItem2b.getShop());
assertEquals(100f, shopItem2b.getPrice(), 0.001f);
}
/**
* Test sync of containment reference (based on problem from 3Dfacto)
*/
@Test
public void testContainmentListSync3() {
final Shop source = ShopFactory.eINSTANCE.createShop();
source.setName("source");
final ShopItem shopItem3a = ShopFactory.eINSTANCE.createShopItem();
shopItem3a.setName("3");
shopItem3a.setPrice(100f);
shopItem3a.setShop(source);
final ShopItem shopItem4a = ShopFactory.eINSTANCE.createShopItem();
shopItem4a.setName("4");
shopItem4a.setPrice(120f);
shopItem4a.setShop(source);
final Shop target = ShopFactory.eINSTANCE.createShop();
target.setName("target");
final ShopItem shopItem1 = ShopFactory.eINSTANCE.createShopItem();
shopItem1.setName("1");
shopItem1.setPrice(100f);
shopItem1.setShop(target);
final ShopItem shopItem2 = ShopFactory.eINSTANCE.createShopItem();
shopItem2.setName("2");
shopItem2.setPrice(100f);
shopItem2.setShop(target);
final ShopItem shopItem3b = ShopFactory.eINSTANCE.createShopItem();
shopItem3b.setName("3");
shopItem3b.setPrice(200f);
shopItem3b.setShop(target);
final ShopItem shopItem4b = ShopFactory.eINSTANCE.createShopItem();
shopItem4b.setName("4");
shopItem4b.setPrice(200f);
shopItem4b.setShop(target);
sync(target, target.getShopItems(), source.getShopItems(), new EObject[] { shopItem1, shopItem2 },
ShopPackage.Literals.SHOP__SHOP_ITEMS, ShopPackage.Literals.SHOP_ITEM__SHOP,
ShopPackage.Literals.SHOP__SHOP_ITEMS, ShopPackage.Literals.SHOP_ITEM__SHOP,
ShopPackage.Literals.SHOP_ITEM__PRICE, ShopPackage.Literals.SHOP_ITEM__PRICE);
assertEquals(2, target.getShopItems().size());
assertEquals(target, shopItem3b.getShop());
assertEquals(target, shopItem4b.getShop());
assertEquals(100f, shopItem3b.getPrice(), 0.001f);
assertEquals(120f, shopItem4b.getPrice(), 0.001f);
}
/**
* Test sync of containment reference (based on problem from 3Dfacto)
*/
@Test
public void testContainmentListSync4() {
final Shop source = ShopFactory.eINSTANCE.createShop();
source.setName("source");
final ShopItem shopItem1a = ShopFactory.eINSTANCE.createShopItem();
shopItem1a.setName("1");
shopItem1a.setPrice(100f);
shopItem1a.setShop(source);
final ShopItem shopItem2a = ShopFactory.eINSTANCE.createShopItem();
shopItem2a.setName("2");
shopItem2a.setPrice(100f);
shopItem2a.setShop(source);
final ShopItem shopItem3a = ShopFactory.eINSTANCE.createShopItem();
shopItem3a.setName("3");
shopItem3a.setPrice(100f);
shopItem3a.setShop(source);
final ShopItem shopItem4a = ShopFactory.eINSTANCE.createShopItem();
shopItem4a.setName("4");
shopItem4a.setPrice(100f);
shopItem4a.setShop(source);
final Shop target = ShopFactory.eINSTANCE.createShop();
target.setName("target");
final ShopItem shopItem1b = ShopFactory.eINSTANCE.createShopItem();
shopItem1b.setName("1");
shopItem1b.setPrice(100f);
shopItem1b.setShop(target);
final ShopItem shopItem3b = ShopFactory.eINSTANCE.createShopItem();
shopItem3b.setName("3");
shopItem3b.setPrice(100f);
shopItem3b.setShop(target);
final ShopItem shopItem2b = ShopFactory.eINSTANCE.createShopItem();
shopItem2b.setName("2");
shopItem2b.setPrice(100f);
shopItem2b.setShop(target);
sync(target, target.getShopItems(), source.getShopItems(), null, ShopPackage.Literals.SHOP__SHOP_ITEMS,
ShopPackage.Literals.SHOP__SHOP_ITEMS);
assertEquals(4, target.getShopItems().size());
assertEquals(target, shopItem1b.getShop());
assertEquals(target, shopItem2b.getShop());
assertEquals(target, shopItem3b.getShop());
assertEquals(target, shopItem4a.getShop());
}
private final List<EStructuralFeature> myChanges = new ArrayList<EStructuralFeature>();
private final EContentAdapter myChangeListener = new EContentAdapter() {
@Override
public void notifyChanged(Notification msg) {
super.notifyChanged(msg);
if (msg.isTouch())
return;
final EStructuralFeature sf = (EStructuralFeature) msg.getFeature();
if (sf == null)
return;
// LogUtils.debug(this,
// ">>> " + sf.getContainerClass().getName() + "." + sf.getName() + ": " + TSEMFUtils.toString(msg));
myChanges.add(sf);
}
};
private <T extends EObject> void sync(T target, T source, Object[] expectedRemovedObjects,
EStructuralFeature... expectedFeatureChanges) {
SyncController controller = null;
try {
myChanges.clear();
target.eAdapters().add(myChangeListener);
controller = EcoreExtendedUtils.sync(null, target, source);
} finally {
target.eAdapters().remove(myChangeListener);
}
final EStructuralFeature[] actualFeatureChanges = myChanges.toArray(new EStructuralFeature[myChanges.size()]);
Arrays.sort(expectedFeatureChanges, EMFTestUtils.SF_COMPARATOR);
Arrays.sort(actualFeatureChanges, EMFTestUtils.SF_COMPARATOR);
assertArrayEquals(expectedFeatureChanges, actualFeatureChanges);
if (expectedRemovedObjects == null) {
assertEquals(null, controller.getRemovedObjects());
} else {
assertNotNull(controller.getRemovedObjects());
final Object[] actualRemovedObjects = controller.getRemovedObjects().toArray(new Object[0]);
Arrays.sort(expectedRemovedObjects, BasicUtils.OBJECT_COMPARATOR);
Arrays.sort(actualRemovedObjects, BasicUtils.OBJECT_COMPARATOR);
assertArrayEquals(expectedFeatureChanges, actualFeatureChanges);
}
}
private <T extends EObject> void sync(EObject targetOwner, EList<T> target, EList<T> source,
Object[] expectedRemovedObjects, EStructuralFeature... expectedFeatureChanges) {
SyncController controller = null;
try {
myChanges.clear();
targetOwner.eAdapters().add(myChangeListener);
controller = EcoreExtendedUtils.sync(null, target, source);
} finally {
targetOwner.eAdapters().remove(myChangeListener);
}
final EStructuralFeature[] actualFeatureChanges = myChanges.toArray(new EStructuralFeature[myChanges.size()]);
Arrays.sort(expectedFeatureChanges, EMFTestUtils.SF_COMPARATOR);
Arrays.sort(actualFeatureChanges, EMFTestUtils.SF_COMPARATOR);
assertArrayEquals(expectedFeatureChanges, actualFeatureChanges);
final List<EObject> removedObjects = controller.getRemovedObjects();
if (expectedRemovedObjects == null || expectedRemovedObjects.length == 0) {
assertEquals(null, removedObjects);
} else {
assertNotNull(removedObjects);
final Object[] actualRemovedObjects = removedObjects.toArray(new Object[0]);
Arrays.sort(expectedRemovedObjects, BasicUtils.OBJECT_COMPARATOR);
Arrays.sort(actualRemovedObjects, BasicUtils.OBJECT_COMPARATOR);
assertArrayEquals(expectedFeatureChanges, actualFeatureChanges);
}
}
}