blob: fedf8546677ca413dd6945f5978fef786d700a21 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016, 2019 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* E.D.Willink - initial API and implementation
*******************************************************************************/
package org.eclipse.qvtd.umlx.tests;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.EMFPlugin;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.URIConverter;
import org.eclipse.emf.ecore.resource.URIHandler;
import org.eclipse.emf.ecore.resource.impl.FileURIHandlerImpl;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.ocl.pivot.Element;
import org.eclipse.ocl.pivot.Import;
import org.eclipse.ocl.pivot.Model;
import org.eclipse.ocl.pivot.OCLExpression;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.VariableDeclaration;
import org.eclipse.ocl.pivot.VariableExp;
import org.eclipse.ocl.pivot.internal.utilities.OCLInternal;
import org.eclipse.ocl.pivot.internal.utilities.PivotUtilInternal;
import org.eclipse.ocl.pivot.utilities.OCL;
import org.eclipse.ocl.pivot.utilities.PivotUtil;
import org.eclipse.ocl.pivot.utilities.TreeIterable;
import org.eclipse.qvtd.compiler.internal.utilities.CompilerUtil;
import org.eclipse.qvtd.pivot.qvtbase.Pattern;
import org.eclipse.qvtd.pivot.qvtbase.Predicate;
import org.eclipse.qvtd.pivot.qvtbase.QVTbaseFactory;
import org.eclipse.qvtd.pivot.qvtbase.utilities.QVTbase;
import org.eclipse.qvtd.pivot.qvtbase.utilities.QVTbaseUtil;
import org.eclipse.qvtd.pivot.qvtrelation.DomainPattern;
import org.eclipse.qvtd.pivot.qvtrelation.QVTrelationFactory;
import org.eclipse.qvtd.pivot.qvtrelation.Relation;
import org.eclipse.qvtd.pivot.qvtrelation.TemplateVariable;
import org.eclipse.qvtd.pivot.qvtrelation.utilities.QVTrelation;
import org.eclipse.qvtd.pivot.qvtrelation.utilities.QVTrelationUtil;
import org.eclipse.qvtd.pivot.qvttemplate.CollectionTemplateExp;
import org.eclipse.qvtd.pivot.qvttemplate.ObjectTemplateExp;
import org.eclipse.qvtd.pivot.qvttemplate.PropertyTemplateItem;
import org.eclipse.qvtd.pivot.qvttemplate.TemplateExp;
import org.eclipse.qvtd.umlx.qvtr2umlx.QVTr2UMLX;
import org.eclipse.qvtd.umlx.umlx2qvtr.UMLX2QVTr;
import org.eclipse.qvtd.umlx.utilities.UMLXStandaloneSetup;
import org.eclipse.qvtd.xtext.qvtbase.tests.LoadTestCase;
import org.eclipse.qvtd.xtext.qvtbase.tests.utilities.TestsXMLUtil;
import org.eclipse.qvtd.xtext.qvtbase.tests.utilities.XtextCompilerUtil;
import com.google.common.collect.Lists;
/**
* Tests that load a model and verify that there are no unresolved proxies as a result.
*/
public class UMLXSerializeTests extends LoadTestCase
{
@Override
protected @NonNull OCLInternal createOCL() {
return QVTbase.newInstance(getTestProjectManager(), null);
}
/* protected void doLoad_QVTr(URI inputURI, URI pivotURI) throws IOException {
OCL ocl = OCL.newInstance(getProjectMap());
doLoad_Concrete(ocl, inputURI, pivotURI, null);
ocl.dispose();
} */
protected void doLoadTest(URI inputURI, URI pivotURI, URI umlxURI) throws Exception {
OCL ocl = OCL.newInstance(getTestProjectManager());
Resource qvtrResource = doLoad_Concrete(ocl, inputURI, pivotURI, null);
Resource umlxResource = qvtrResource.getResourceSet().createResource(umlxURI);
QVTr2UMLX qvtr2umlx = new QVTr2UMLX(ocl.getEnvironmentFactory(), qvtrResource, umlxResource);
qvtr2umlx.transform();
umlxResource.save(null);
//
assertNoValidationErrors(umlxURI.toString(), umlxResource);
//
ocl.dispose();
}
protected void doRoundTripTest(@NonNull String path, @NonNull String stem, boolean skipCompare) throws Exception {
QVTrelation ocl1 = QVTrelation.newInstance(getTestProjectManager());
URI inputURI1 = getResourceURI(path + stem + ".qvtr");
URI pivotURI1 = getTestURI(stem + ".qvtras");
URI umlxURI = getTestURI(path + stem + ".umlx");
URI pivotURI2 = getTestURI(stem + ".regenerated.qvtras");
URIConverter uriConverter = ocl1.getResourceSet().getURIConverter();
URI normalizedURI = uriConverter.normalize(umlxURI);
URIHandler uriHandler = uriConverter.getURIHandler(normalizedURI);
if (!(uriHandler instanceof FileURIHandlerImpl)) { // platform:/plugin on Hudson
umlxURI = getTestURI(stem + ".umlx");
}
Resource qvtrResource1 = doLoad_Concrete(ocl1, inputURI1, pivotURI1, null);
Resource umlxResource1 = qvtrResource1.getResourceSet().createResource(umlxURI);
QVTr2UMLX qvtr2umlx = new QVTr2UMLX(ocl1.getEnvironmentFactory(), qvtrResource1, umlxResource1);
qvtr2umlx.transform();
umlxResource1.save(null);
//
assertNoValidationErrors(umlxURI.toString(), umlxResource1);
ocl1.deactivate();
//
QVTrelation ocl2 = QVTrelation.newInstance(getTestProjectManager());
Resource umlxResource2 = ocl2.getResourceSet().getResource(umlxURI, true);
Resource qvtrResource2 = ocl2.getMetamodelManager().getASResourceSet().createResource(pivotURI2);
UMLX2QVTr umlx2qvtr = new UMLX2QVTr(ocl2.getEnvironmentFactory(), umlxResource2, qvtrResource2);
umlx2qvtr.transform();
qvtrResource2.save(CompilerUtil.defaultSavingOptions);
//
Model asModel1 = PivotUtil.getModel(qvtrResource1);
Model asModel2 = PivotUtil.getModel(qvtrResource2);
asModel2.setName(asModel1.getName());
asModel2.setExternalURI(asModel1.getExternalURI());
TestsXMLUtil.resetTransients(qvtrResource1);
TestsXMLUtil.resetTransients(qvtrResource2);
normalize(qvtrResource1);
normalize(qvtrResource2);
if (!skipCompare) { // FIXME BUG 511230
assertSameModel(qvtrResource1, qvtrResource2);
}
ocl1.dispose();
ocl2.dispose();
}
private void normalize(@NonNull Resource qvtrResource) {
for (TreeIterator<EObject> tit = qvtrResource.getAllContents(); tit.hasNext(); ) {
EObject eObject = tit.next();
if (eObject instanceof Relation) {
normalizeRelation((Relation)eObject);
tit.prune();
}
else if (eObject instanceof Import) {
((Import)eObject).getOwnedComments().clear();
tit.prune();
}
}
}
/**
* For non-composed leaf template elements there is a free choice to use a shared or template variable. Since there may be multiple
* candidate sites for the template variable, normalize by using a shared variable.
*/
private void normalizeRelation(@NonNull Relation asRelation) {
//
// Find all references to all variables within the Relation
//
Map<@NonNull VariableDeclaration, @NonNull List<@NonNull Element>> variable2reference = new HashMap<>();
List<OCLExpression> whenExpressions = new ArrayList<>();
// whenExpressions.add(asRelation.getWhen());
for (@NonNull EObject eObject : new TreeIterable(asRelation, true)) {
List<@NonNull VariableDeclaration> referredVariables = null;
if (eObject instanceof VariableExp) {
referredVariables = Lists.newArrayList(((VariableExp)eObject).getReferredVariable());
}
else if (eObject instanceof TemplateExp) {
TemplateExp templateExp = (TemplateExp)eObject;
referredVariables = Lists.newArrayList(templateExp.getBindsTo());
if (eObject instanceof CollectionTemplateExp) {
referredVariables.add(((CollectionTemplateExp)eObject).getRest());
}
OCLExpression where = templateExp.getWhere();
if (where != null) {
whenExpressions.add(where);
}
}
else if (eObject instanceof DomainPattern) {
referredVariables = Lists.newArrayList(((DomainPattern)eObject).getBindsTo());
}
if (referredVariables != null) {
for (@NonNull VariableDeclaration referredVariable : referredVariables) {
List<@NonNull Element> references = variable2reference.get(referredVariable);
if (references == null) {
references = new ArrayList<>();
variable2reference.put(referredVariable, references);
}
references.add((Element)eObject);
}
}
}
//
// Replace leaf non-composite template variables
//
for (@NonNull VariableDeclaration variable : variable2reference.keySet()) {
List<@NonNull Element> references = variable2reference.get(variable);
assert references != null;
if (variable instanceof TemplateVariable) {
boolean canBeShared = true;
for (@NonNull Element reference : references) {
if (reference instanceof TemplateExp) {
EObject eContainer = reference.eContainer();
if (eContainer instanceof PropertyTemplateItem) {
if (reference instanceof ObjectTemplateExp) {
ObjectTemplateExp objectTemplateExp = (ObjectTemplateExp)reference;
if (!objectTemplateExp.getPart().isEmpty()) {
canBeShared = false;
break;
}
Property asProperty = QVTrelationUtil.getReferredProperty(((PropertyTemplateItem)eContainer));
if ((asProperty == null) || asProperty.isIsComposite()) {
// perhaps this needs a further is there a when/where reference??
// canBeShared = false;
// break;
}
}
else if (reference instanceof CollectionTemplateExp) {
CollectionTemplateExp collectionTemplateExp = (CollectionTemplateExp)reference;
if (!collectionTemplateExp.getMember().isEmpty()) {
canBeShared = false;
break;
}
if (collectionTemplateExp.getRest() != null) {
canBeShared = false;
break;
}
}
}
else {
canBeShared = false;
break;
}
}
// EReference eContainmentFeature = reference.eContainmentFeature();
// EClassifier eType = eContainmentFeature.getEType();
// if (!eType.isInstance(PivotPackage.Literals.OCL_EXPRESSION)) {
// canBeShared = false;
// break;
// }
}
if (canBeShared) {
VariableDeclaration sharedVariable = QVTrelationFactory.eINSTANCE.createSharedVariable();
sharedVariable.setName(variable.getName());
sharedVariable.setType(variable.getType());
// sharedVariable.setIsImplicit(variable.isIsImplicit());
sharedVariable.setIsRequired(variable.isIsRequired());
// sharedVariable.setOwnedInit(variable.get);
QVTbaseUtil.replaceChild(variable, sharedVariable);
for (@NonNull Element reference : references) {
if (reference instanceof VariableExp) {
((VariableExp)reference).setReferredVariable(sharedVariable);
}
else if (reference instanceof ObjectTemplateExp) {
QVTbaseUtil.replaceChild(reference, PivotUtil.createVariableExp(sharedVariable));
}
else if (reference instanceof CollectionTemplateExp) {
QVTbaseUtil.replaceChild(reference, PivotUtil.createVariableExp(sharedVariable));
}
else if (reference instanceof DomainPattern) {
((DomainPattern)reference).getBindsTo().remove(variable);
}
}
}
}
}
//
// Replace domain where's by relation when's
//
Pattern whenPattern = asRelation.getWhen();
for (OCLExpression whenExpression : whenExpressions) {
PivotUtilInternal.resetContainer(whenExpression);
Predicate asPredicate = QVTbaseFactory.eINSTANCE.createPredicate();
asPredicate.setConditionExpression(whenExpression);
if (whenPattern == null) {
whenPattern = QVTbaseFactory.eINSTANCE.createPattern();
asRelation.setWhen(whenPattern);
}
whenPattern.getPredicate().add(asPredicate);
}
}
@Override
protected void setUp() throws Exception {
XtextCompilerUtil.doQVTrelationSetup();
if (!EMFPlugin.IS_ECLIPSE_RUNNING) {
UMLXStandaloneSetup.doSetup();
}
super.setUp();
}
public void testUMLXLoad_Forward2Reverse_qvtr() throws Exception {
URI inputURI = getResourceURI("org.eclipse.qvtd.xtext.qvtrelation.tests/models/forward2reverse/Forward2Reverse.qvtr");
URI pivotURI = getTestURI("Forward2Reverse.qvtras");
URI umlxURI = getTestURI("Forward2Reverse.umlx");
doLoadTest(inputURI, pivotURI, umlxURI);
}
public void testUMLXLoad_Keys_qvtr() throws Exception {
URI inputURI = getResourceURI("org.eclipse.qvtd.xtext.qvtrelation.tests/models/misc/Keys.qvtr");
URI pivotURI = getTestURI("Keys.qvtras");
URI umlxURI = getTestURI("Keys.umlx");
doLoadTest(inputURI, pivotURI, umlxURI);
}
public void testUMLXLoad_RelToCore_qvtr() throws Exception {
URI inputURI = getResourceURI("org.eclipse.qvtd.examples.qvtrelation.reltocore/model/RelToCore.qvtr");
URI pivotURI = getTestURI("RelToCore.qvtras");
URI umlxURI = getTestURI("RelToCore.umlx");
doLoadTest(inputURI, pivotURI, umlxURI);
}
public void testUMLXLoad_SeqToStm_qvtr() throws Exception {
URI inputURI = getResourceURI("org.eclipse.qvtd.xtext.qvtrelation.tests/models/seq2stm/SeqToStm.qvtr");
URI pivotURI = getTestURI("SeqToStm.qvtras");
URI umlxURI = getTestURI("SeqToStm.umlx");
doLoadTest(inputURI, pivotURI, umlxURI);
}
public void testUMLXLoad_SimplerRelToCore_qvtr() throws Exception {
URI inputURI = getResourceURI("org.eclipse.qvtd.examples.qvtrelation.reltocore/model/SimplerRelToCore.qvtr");
URI pivotURI = getTestURI("SimplerRelToCore.qvtras");
URI umlxURI = getTestURI("SimplerRelToCore.umlx");
doLoadTest(inputURI, pivotURI, umlxURI);
}
public void testUMLXRoundtrip_Forward2Reverse_qvtr() throws Exception {
doRoundTripTest("org.eclipse.qvtd.xtext.qvtrelation.tests/models/forward2reverse/", "Forward2Reverse", true);
}
public void testUMLXRoundtrip_HierarchicalStateMachine2FlatStateMachine_qvtr() throws Exception {
doRoundTripTest("org.eclipse.qvtd.xtext.qvtrelation.tests/models/hstm2fstm/", "HierarchicalStateMachine2FlatStateMachine", true);
}
public void testUMLXRoundtrip_Iterated2Iterated_qvtr() throws Exception {
doRoundTripTest("org.eclipse.qvtd.xtext.qvtrelation.tests/models/iterated2iterated/", "Iterated2Iterated", true);
}
public void testUMLXRoundtrip_Keys_qvtr() throws Exception {
doRoundTripTest("org.eclipse.qvtd.xtext.qvtrelation.tests/models/misc/", "Keys", true);
}
public void testUMLXRoundtrip_MiToSiSimple_qvtr() throws Exception {
doRoundTripTest("org.eclipse.qvtd.xtext.qvtrelation.tests/models/mitosi/", "MiToSiSimple", true);
}
public void testUMLXRoundtrip_PN2SC_qvtr() throws Exception {
doRoundTripTest("org.eclipse.qvtd.xtext.qvtrelation.tests/models/pn2sc/", "PetriNet2StateChart", true);
}
public void testUMLXRoundtrip_SeqToStm_qvtr() throws Exception {
// BaseLinkingService.DEBUG_RETRY.setState(true);
doRoundTripTest("org.eclipse.qvtd.xtext.qvtrelation.tests/models/seq2stm/", "SeqToStm", true);
}
public void testUMLXRoundtrip_SimplerRelToCore_qvtr() throws Exception {
doRoundTripTest("org.eclipse.qvtd.examples.qvtrelation.reltocore/model/", "SimplerRelToCore", true);
}
}