/*
* Copyright (c) 2006, 2009 Borland Software Corporation
*
* 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:
* Artem Tikhomirov (Borland) - initial API and implementation
* Anna Karjakina (Borland) - tests for MigrationDelegate
*/
package org.eclipse.gmf.tests.migration;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import junit.framework.TestCase;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.ContentHandler;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.EcoreValidator;
import org.eclipse.gmf.internal.common.migrate.MigrationDelegate;
import org.eclipse.gmf.internal.common.migrate.MigrationDelegateImpl;
import org.eclipse.gmf.internal.common.migrate.MigrationResource;
/**
* @author artem
*/
public class GenericMigrationTest extends TestCase {
private EAttribute myAttrToRemove;
private EAttribute myAttrToRename;
private EReference myWidenedRef1;
private EReference myWidenedRef2;
private EAttribute myAttrNarrow;
private EAttribute myAttrNarrowChild;
public GenericMigrationTest(String name) {
super(name);
}
@Override
protected void setUp() throws Exception {
super.setUp();
createMetaModel();
}
private EPackage createMetaModel() {
EPackage mmPackage = EcoreFactory.eINSTANCE.createEPackage();
EClass mClass = EcoreFactory.eINSTANCE.createEClass();
myAttrToRemove = EcoreFactory.eINSTANCE.createEAttribute();
myAttrToRename = EcoreFactory.eINSTANCE.createEAttribute();
myWidenedRef1 = EcoreFactory.eINSTANCE.createEReference();
myWidenedRef2 = EcoreFactory.eINSTANCE.createEReference();
myAttrNarrow = EcoreFactory.eINSTANCE.createEAttribute();
myAttrNarrowChild = EcoreFactory.eINSTANCE.createEAttribute();
EClass mNarrowClass = EcoreFactory.eINSTANCE.createEClass();
EClass mNarrowClassChild = EcoreFactory.eINSTANCE.createEClass();
mNarrowClassChild.getESuperTypes().add(mNarrowClass);
mmPackage.getEClassifiers().add(mClass);
mmPackage.getEClassifiers().add(mNarrowClass);
mmPackage.getEClassifiers().add(mNarrowClassChild);
mClass.getEStructuralFeatures().add(myAttrToRemove);
mClass.getEStructuralFeatures().add(myAttrToRename);
mClass.getEStructuralFeatures().add(myWidenedRef1);
mClass.getEStructuralFeatures().add(myWidenedRef2);
mNarrowClass.getEStructuralFeatures().add(myAttrNarrow);
mNarrowClassChild.getEStructuralFeatures().add(myAttrNarrowChild);
mmPackage.setName("MM1");
mmPackage.setNsPrefix("mm");
mmPackage.setNsURI("uri:/mm/1");
mClass.setName("MClass");
mNarrowClass.setName("NarrowClass");
mNarrowClassChild.setName("NarrowClassChild");
myAttrToRemove.setName("myRemovedAttr");
myAttrToRemove.setEType(EcorePackage.eINSTANCE.getEString());
myAttrToRename.setName("myRenamedAttr");
myAttrToRename.setEType(EcorePackage.eINSTANCE.getEString());
myWidenedRef1.setName("myWidenedRef1");
myWidenedRef1.setUpperBound(-1);
myWidenedRef1.setContainment(true);
myWidenedRef1.setEType(mNarrowClass);
myWidenedRef2.setName("myWidenedRef2");
myWidenedRef2.setUpperBound(-1);
myWidenedRef2.setContainment(true);
myWidenedRef2.setEType(mNarrowClass);
myAttrNarrow.setName("myNarrowAttr");
myAttrNarrow.setEType(EcorePackage.eINSTANCE.getEString());
myAttrNarrowChild.setName("myNarrowChildAttr");
myAttrNarrowChild.setLowerBound(1);
myAttrNarrowChild.setEType(EcorePackage.eINSTANCE.getEString());
return mmPackage;
}
private EObject newInstance() {
return getMetaModel().getEFactoryInstance().create(myAttrToRemove.getEContainingClass());
}
private EObject newNarrowInstance() {
return getMetaModel().getEFactoryInstance().create(myAttrNarrow.getEContainingClass());
}
private EObject newNarrowChildInstance() {
return getMetaModel().getEFactoryInstance().create(myAttrNarrowChild.getEContainingClass());
}
private EPackage getMetaModel() {
return myWidenedRef1.getEContainingClass().getEPackage();
}
private boolean checkResourceHasNoProblems(Resource migratedResource) {
assertNotNull(migratedResource);
assertTrue(migratedResource.getErrors().isEmpty());
if (migratedResource instanceof MigrationResource) {
assertFalse(migratedResource.getWarnings().isEmpty());
assertEquals(1, migratedResource.getWarnings().size());
assertTrue(migratedResource.getWarnings().get(0) instanceof MigrationResource.Diagnostic);
} else {
assertTrue(migratedResource.getWarnings().isEmpty());
}
boolean validate = true;
for (Iterator<EObject> it=migratedResource.getAllContents(); it.hasNext() && validate;) {
validate = EcoreValidator.INSTANCE.validate(it.next(), null, null);
}
return validate;
}
private String assertLoadingProblemsAfterMetamodelChanges(EPackage metamodel, URI modelResource) {
String errorMessage = null;
// try to load mm
try {
ResourceSetImpl rset = new ResourceSetImpl();
rset.getPackageRegistry().put(metamodel.getNsURI(), metamodel);
Resource resource = rset.createResource(modelResource, ContentHandler.UNSPECIFIED_CONTENT_TYPE);
resource.load(null);
fail("Load should fail because of metamodel changes");
} catch (RuntimeException ex) {
// expected
assertNotNull(ex.getMessage());
errorMessage = ex.getMessage();
} catch (IOException ex) {
// expected
assertNotNull(ex.getMessage());
errorMessage = ex.getMessage();
}
return errorMessage;
}
private URI saveToResource(EPackage metamodel, String filenameStart, String fileextension, EObject... rootObjects) {
URI uri = null;
Collection<EObject> roots = Arrays.asList(rootObjects);
try {
uri = URI.createFileURI(File.createTempFile(filenameStart, fileextension.startsWith(".") ? fileextension : "."+fileextension).getAbsolutePath());
ResourceSetImpl resourceSetImpl = new ResourceSetImpl();
resourceSetImpl.getPackageRegistry().put(metamodel.getNsURI(), metamodel);
Resource res = resourceSetImpl.createResource(uri, ContentHandler.UNSPECIFIED_CONTENT_TYPE);
res.getContents().addAll(roots);
res.save(null);
resourceSetImpl.getResources().removeAll(roots);
} catch (IOException ex) {
fail(ex.toString());
}
return uri;
}
protected void checkNarrowedInstanceAttribute(EObject narrowInstance, EAttribute attribute, String attrValue) {
assertEquals(narrowInstance.eClass(), attribute.getEContainingClass());
assertTrue(narrowInstance.eIsSet(attribute));
Object haveValue = narrowInstance.eGet(attribute, true);
assertEquals(attrValue, haveValue);
}
protected List<EObject> checkReferenceIsNarrowed(EObject migratedObj, EReference widenedRef) {
List<EObject> result = null;
assertTrue(migratedObj.eIsSet(widenedRef));
Object narrowRef = migratedObj.eGet(widenedRef, true);
if (widenedRef.isMany()) {
result = new ArrayList<EObject>();
assertTrue(narrowRef instanceof EList<?>);
EList<?> narrowRefs = (EList<?>) narrowRef;
assertFalse(narrowRefs.isEmpty());
for (int i=0; i<narrowRefs.size(); i++) {
Object migratedNarrowRefs = narrowRefs.get(i);
assertTrue(migratedNarrowRefs instanceof EObject);
EObject narrowInstance = (EObject) migratedNarrowRefs;
result.add(narrowInstance);
}
} else {
assertTrue(narrowRef instanceof EObject);
EObject narrowInstance = (EObject) narrowRef;
result = Collections.singletonList(narrowInstance);
}
return result;
}
private void checkInstanceClassChanged(EObject narrowInstance, EReference widenedReference) {
assertFalse(narrowInstance.eClass().isAbstract());
assertFalse(narrowInstance.eClass().equals(widenedReference.getEType()));
}
private void widenReferenceTypeFrom(EReference refToBeWiden, EClass containingClass, EPackage metamodel) {
EClass mWideClass = EcoreFactory.eINSTANCE.createEClass();
refToBeWiden.getEContainingClass().getEPackage().getEClassifiers().add(mWideClass);
mWideClass.setName("WideClass");
mWideClass.setAbstract(true);
refToBeWiden.setEType(mWideClass);
EList<EClass> supertypes = containingClass.getESuperTypes();
if (!supertypes.contains(mWideClass)) {
supertypes.add(mWideClass);
}
}
private EList<EObject> create2DifferentReferences(String attrValue, String attrChildValue) {
final EList<EObject> narrowInstances = new BasicEList<EObject>();
if (attrValue != null) {
EObject narrowInstance = newNarrowInstance();
narrowInstance.eSet(myAttrNarrow, attrValue);
narrowInstances.add(narrowInstance);
}
if (attrChildValue != null) {
EObject narrowChildInstance = newNarrowChildInstance();
narrowChildInstance.eSet(myAttrNarrowChild, attrChildValue);
narrowInstances.add(narrowChildInstance);
}
return narrowInstances;
}
private EList<EObject> createNarrowReferences(String attrValue) {
final EList<EObject> narrowInstances = new BasicEList<EObject>();
if (attrValue != null) {
EObject narrowInstance = newNarrowInstance();
narrowInstance.eSet(myAttrNarrow, attrValue);
narrowInstances.add(narrowInstance);
}
return narrowInstances;
}
private EObject createRootWithReferences(EReference reference, EList<EObject> referenceValues) {
final EObject testObject1 = newInstance();
testObject1.eSet(reference, referenceValues);
return testObject1;
}
public void testRemovedAttribute() {
final EObject testObject = newInstance();
testObject.eSet(myAttrToRemove, "value");
EPackage metamodel = getMetaModel();
URI uri = saveToResource(metamodel, "removed", "tests", testObject);
// remove attr from metamodel
myAttrToRemove.getEContainingClass().getEStructuralFeatures().remove(myAttrToRemove);
String errorMessage = assertLoadingProblemsAfterMetamodelChanges(metamodel, uri);
assertTrue(errorMessage.contains(myAttrToRemove.getName()));
final MigrationDelegateImpl delegate = new MigrationDelegateImpl();
delegate.registerDeletedAttributes(testObject.eClass(), myAttrToRemove.getName());
Resource migrated = loadMigrationResource(metamodel, delegate, uri);
checkResourceHasNoProblems(migrated);
assertEquals(1, migrated.getContents().size());
EObject migratedObj = migrated.getContents().get(0);
assertEquals(testObject.eClass(), migratedObj.eClass());
}
public void testWidenedReference() {
final String attrValue = "narrow value";
final EList<EObject> narrowValues = createNarrowReferences(attrValue);
final EObject testObject = createRootWithReferences(myWidenedRef1, narrowValues);
EPackage metamodel = getMetaModel();
URI uri = saveToResource(metamodel, "widened", "tests", testObject);
// widen reference in metamodel
widenReferenceTypeFrom(myWidenedRef1, myAttrNarrow.getEContainingClass(), metamodel);
// try to load mm
String errorMessage = assertLoadingProblemsAfterMetamodelChanges(getMetaModel(), uri);
//assertTrue(errorMessage.contains(myWidenedRef1.getEType().getName())); //XXX check
MigrationDelegateImpl delegate = new MigrationDelegateImpl();
delegate.registerNarrowedAbstractType(myWidenedRef1.getEType().getName(), myAttrNarrow.getEContainingClass());
// try to load mm
Resource migrated = loadMigrationResource(metamodel, delegate, uri);
checkResourceHasNoProblems(migrated);
assertEquals(1, migrated.getContents().size());
EObject migratedObj = migrated.getContents().get(0);
assertEquals(testObject.eClass(), migratedObj.eClass());
List<EObject> narrowed = checkReferenceIsNarrowed(migratedObj, myWidenedRef1);
assertEquals(1, narrowed.size());
EObject narrowInstance = narrowed.get(0);
checkInstanceClassChanged(narrowInstance, myWidenedRef1);
checkNarrowedInstanceAttribute(narrowInstance, myAttrNarrow, attrValue);
}
public void testWidenedReferenceWith2Types() {
final String attrValue = "narrow value";
final String attrChildValue = "narrow child value";
final EList<EObject> narrowValues = create2DifferentReferences(attrValue, attrChildValue);
final EObject testObject = createRootWithReferences(myWidenedRef1, narrowValues);
EPackage metamodel = getMetaModel();
URI uri = saveToResource(metamodel, "widened2Types", "tests", testObject);
// widen reference in metamodel
widenReferenceTypeFrom(myWidenedRef1, myAttrNarrow.getEContainingClass(), metamodel);
// try to load mm
String errorMessage = assertLoadingProblemsAfterMetamodelChanges(metamodel, uri);
// assertTrue(errorMessage.contains(myWidenedRef1.getEType().getName())); //XXX
MigrationDelegateImpl delegate = new MigrationDelegateImpl();
delegate.registerNarrowedAbstractType(myWidenedRef1.getEType().getName(), myAttrNarrow.getEContainingClass());
// try to load mm
Resource migrated = loadMigrationResource(metamodel, delegate, uri);
checkResourceHasNoProblems(migrated);
assertEquals(1, migrated.getContents().size());
EObject migratedObj = migrated.getContents().get(0);
assertEquals(testObject.eClass(), migratedObj.eClass());
List<EObject> narrowed = checkReferenceIsNarrowed(migratedObj, myWidenedRef1);
assertEquals(2, narrowed.size());
EObject narrowInstance1 = narrowed.get(0);
checkInstanceClassChanged(narrowInstance1, myWidenedRef1);
checkNarrowedInstanceAttribute(narrowInstance1, myAttrNarrow, attrValue);
EObject narrowInstance2 = narrowed.get(1);
checkInstanceClassChanged(narrowInstance2, myWidenedRef1);
checkNarrowedInstanceAttribute(narrowInstance2, myAttrNarrowChild, attrChildValue);
}
public void test2WidenedReferences() {
final String attrValue1 = "narrow value 1";
final EList<EObject> narrowValues1 = createNarrowReferences(attrValue1);
final EObject testObject1 = createRootWithReferences(myWidenedRef1, narrowValues1);
final String attrValue2 = "narrow value 2";
final String attrChildValue2 = "narrow child value 2";
final EList<EObject> narrowValues2 = create2DifferentReferences(attrValue2, attrChildValue2);
final EObject testObject2 = createRootWithReferences(myWidenedRef2, narrowValues2);
final String attrValue3 = "narrow value 3";
final EList<EObject> narrowValues3 = createNarrowReferences(attrValue3);
final EObject testObject3 = createRootWithReferences(myWidenedRef1, narrowValues3);
final String attrValue4 = "narrow value 4";
final EList<EObject> narrowValues4 = createNarrowReferences(attrValue4);
final EObject testObject4 = createRootWithReferences(myWidenedRef2, narrowValues4);
EPackage metamodel = getMetaModel();
URI uri = saveToResource(metamodel, "widened2Refs", "tests", testObject1, testObject2, testObject3, testObject4);
// widen reference in metamodel
widenReferenceTypeFrom(myWidenedRef1, myAttrNarrow.getEContainingClass(), metamodel);
widenReferenceTypeFrom(myWidenedRef2, myAttrNarrow.getEContainingClass(), metamodel);
// try to load mm
String errorMessage = assertLoadingProblemsAfterMetamodelChanges(metamodel, uri);
// assertTrue(errorMessage.contains(myAttrNarrow.getName())); //XXX
MigrationDelegateImpl delegate = new MigrationDelegateImpl();
delegate.registerNarrowedAbstractType(myWidenedRef1.getEType().getName(), myAttrNarrow.getEContainingClass());
delegate.registerNarrowedAbstractType(myWidenedRef2.getEType().getName(), myAttrNarrow.getEContainingClass());
// try to load mm
Resource migrated = loadMigrationResource(metamodel, delegate, uri);
checkResourceHasNoProblems(migrated);
assertEquals(4, migrated.getContents().size());
EObject migratedObj1 = migrated.getContents().get(0);
assertEquals(testObject1.eClass(), migratedObj1.eClass());
List<EObject> narrowed1 = checkReferenceIsNarrowed(migratedObj1, myWidenedRef1);
assertEquals(1, narrowed1.size());
checkReferenceIsNarrowed(migratedObj1, myWidenedRef1);
EObject narrowed1first = narrowed1.get(0);
checkNarrowedInstanceAttribute(narrowed1first, myAttrNarrow, attrValue1);
EObject migratedObj2 = migrated.getContents().get(1);
assertEquals(testObject2.eClass(), migratedObj2.eClass());
List<EObject> narrowed2 = checkReferenceIsNarrowed(migratedObj2, myWidenedRef2);
assertEquals(2, narrowed2.size());
checkReferenceIsNarrowed(migratedObj2, myWidenedRef2);
EObject narrowed2first = narrowed2.get(0);
checkNarrowedInstanceAttribute(narrowed2first, myAttrNarrow, attrValue2);
EObject narrowed2second = narrowed2.get(1);
checkNarrowedInstanceAttribute(narrowed2second, myAttrNarrowChild, attrChildValue2);
EObject migratedObj3 = migrated.getContents().get(2);
assertEquals(testObject3.eClass(), migratedObj3.eClass());
List<EObject> narrowed3 = checkReferenceIsNarrowed(migratedObj3, myWidenedRef1);
assertEquals(1, narrowed3.size());
checkReferenceIsNarrowed(migratedObj3, myWidenedRef1);
EObject narrowed3first = narrowed3.get(0);
checkNarrowedInstanceAttribute(narrowed3first, myAttrNarrow, attrValue3);
EObject migratedObj4 = migrated.getContents().get(3);
assertEquals(testObject4.eClass(), migratedObj4.eClass());
List<EObject> narrowed4 = checkReferenceIsNarrowed(migratedObj4, myWidenedRef2);
assertEquals(1, narrowed3.size());
checkReferenceIsNarrowed(migratedObj4, myWidenedRef2);
EObject narrowed4first = narrowed4.get(0);
checkNarrowedInstanceAttribute(narrowed4first, myAttrNarrow, attrValue4);
}
public void testWidenedReferenceWithDifferentDefaults() {
// create model based on current metamodel
String attrValue = "narrow value";
String attrChildValue = "narrow child value";
final EList<EObject> narrowValues = create2DifferentReferences(attrValue, attrChildValue);
final EObject testObject = createRootWithReferences(myWidenedRef1, narrowValues);
EPackage metamodel = getMetaModel();
URI uri = saveToResource(metamodel, "widened2Defaults", "tests", testObject);
// try to load mm
try {
ResourceSetImpl resourceSetImpl = new ResourceSetImpl();
resourceSetImpl.getPackageRegistry().put(metamodel.getNsURI(), metamodel);
Resource ordinaryResource = resourceSetImpl.createResource(uri, ContentHandler.UNSPECIFIED_CONTENT_TYPE);
ordinaryResource.load(null);
boolean validate = checkResourceHasNoProblems(ordinaryResource);
assertTrue("Should not fail with obligatory metamodel attribute not set", validate);
} catch (RuntimeException ex) {
fail();
} catch (IOException ex) {
fail();
}
MigrationDelegateImpl badDelegate = new MigrationDelegateImpl();
badDelegate.registerNarrowedAbstractType(myWidenedRef1.getEType().getName(), myAttrNarrowChild.getEContainingClass());
// try to load mm
Resource badMigrated = loadMigrationResource(getMetaModel(), badDelegate, uri);
checkResourceHasNoProblems(badMigrated);
boolean validateBad = checkResourceHasNoProblems(badMigrated);
assertFalse("Should fail with obligatory metamodel attribute not set", validateBad);
/*
MigrationDelegateImpl delegate = new MigrationDelegateImpl() {
{
registerNarrowedAbstractType(myWidenedRef1.getEType().getName(), myAttrNarrowChild.getEContainingClass());
}
private Collection<EObject> myToBeChecked = new ArrayList<EObject>();
@Override
public void processObject(EObject result) {
super.processObject(result);
if (myAttrNarrowChild.getEContainingClass().equals(result.eClass())) {
myToBeChecked.add(result);
}
}
@Override
public void preResolve() {
super.preResolve();
for (EObject narrowed : myToBeChecked) {
if (!narrowed.eIsSet(myAttrNarrowChild)) {
EObject defaultTyped = narrowed.eClass().getEPackage().getEFactoryInstance().create((EClass) myWidenedRef1.getEType());
for (EStructuralFeature feature : narrowed.eClass().getEAllStructuralFeatures()) {
if (narrowed.eIsSet(feature)) {
defaultTyped.eSet(feature, narrowed.eGet(feature));
}
}
EObject parent = narrowed.eContainer();
@SuppressWarnings("unchecked")
EList<EObject> children = (EList<EObject>) parent.eGet(myWidenedRef1);
int index = children.indexOf(narrowed);
children.remove(narrowed);
children.add(index, defaultTyped);
}
}
}
};
// try to load mm
Resource migrated = loadMigrationResource(getMetaModel(), delegate, uri);
checkResourceHasNoProblems(migrated);
boolean validate = checkResourceHasNoProblems(migrated);
assertTrue("Should not fail with obligatory metamodel attribute not set", validate);
assertEquals(1, migrated.getContents().size());
EObject migratedObj = migrated.getContents().get(0);
assertEquals(testObject.eClass(), migratedObj.eClass());
List<EObject> narrowed = checkReferenceIsNarrowed(migratedObj, myWidenedRef1);
assertEquals(2, narrowed.size());
EObject narrowInstance1 = narrowed.get(0);
assertFalse(narrowInstance1.eClass().isAbstract());
assertTrue(narrowInstance1.eClass().equals(myWidenedRef1.getEType()));
checkNarrowedInstanceAttribute(narrowInstance1, myAttrNarrow, attrValue);
EObject narrowInstance2 = narrowed.get(1);
checkInstanceClassChanged(narrowInstance2, myWidenedRef1);
checkNarrowedInstanceAttribute(narrowInstance2, myAttrNarrowChild, attrChildValue);
*/
}
private Resource loadMigrationResource(EPackage metamodel, MigrationDelegate delegate, URI modelResourceURI) {
if(modelResourceURI == null) {
throw new IllegalArgumentException("null resource uri"); //$NON-NLS-1$
}
ResourceSetImpl rset = new ResourceSetImpl();
rset.getResources().add(createMigrationResource(delegate, modelResourceURI));
rset.getPackageRegistry().put(metamodel.getNsURI(), metamodel);
return rset.getResource(modelResourceURI, true);
}
private Resource createMigrationResource(final MigrationDelegate delegate, URI modelResourceURI) {
return new MigrationResource(modelResourceURI) {
protected MigrationDelegate createDelegate() {
return delegate;
}
};
}
}