/**
* Copyright (c) 2012-2016 Marsha Chechik, Alessio Di Sandro, Michalis Famelis,
* Rick Salay.
* 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:
* Alessio Di Sandro - Implementation.
*/
package edu.toronto.cs.se.modelepedia.tests;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Map;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Platform;
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.compare.Comparison;
import org.eclipse.emf.compare.EMFCompare;
import org.eclipse.emf.compare.scope.DefaultComparisonScope;
import org.eclipse.emf.compare.scope.IComparisonScope;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.junit.Assert;
import org.junit.Test;
import org.osgi.framework.Bundle;
import edu.toronto.cs.se.mmint.MMINT;
import edu.toronto.cs.se.mmint.MMINTException;
import edu.toronto.cs.se.mmint.MIDTypeHierarchy;
import edu.toronto.cs.se.mmint.MIDTypeRegistry;
import edu.toronto.cs.se.mmint.mid.EMFInfo;
import edu.toronto.cs.se.mmint.mid.ExtendibleElementConstraint;
import edu.toronto.cs.se.mmint.mid.MID;
import edu.toronto.cs.se.mmint.mid.MIDFactory;
import edu.toronto.cs.se.mmint.mid.MIDLevel;
import edu.toronto.cs.se.mmint.mid.MIDPackage;
import edu.toronto.cs.se.mmint.mid.Model;
import edu.toronto.cs.se.mmint.mid.ModelElement;
import edu.toronto.cs.se.mmint.mid.operator.Operator;
import edu.toronto.cs.se.mmint.mid.operator.OperatorFactory;
import edu.toronto.cs.se.mmint.mid.operator.OperatorGeneric;
import edu.toronto.cs.se.mmint.mid.operator.OperatorInput;
import edu.toronto.cs.se.mmint.mid.relationship.Mapping;
import edu.toronto.cs.se.mmint.mid.relationship.MappingReference;
import edu.toronto.cs.se.mmint.mid.relationship.ModelElementEndpoint;
import edu.toronto.cs.se.mmint.mid.relationship.ModelElementReference;
import edu.toronto.cs.se.mmint.mid.relationship.ModelEndpointReference;
import edu.toronto.cs.se.mmint.mid.utils.FileUtils;
import edu.toronto.cs.se.mmint.mid.utils.MIDOperatorIOUtils;
import edu.toronto.cs.se.mmint.mid.utils.MIDRegistry;
import edu.toronto.cs.se.mmint.mid.utils.MIDTypeFactory;
import edu.toronto.cs.se.modelepedia.kleisli.KleisliModelEndpoint;
import edu.toronto.cs.se.modelepedia.kleisli.KleisliModelEndpointReference;
import edu.toronto.cs.se.modelepedia.kleisli.KleisliModelRel;
//TODO MMINT[TRAVIS] Run test as part of the build
public class KleisliTest extends MMINTTest {
private final static String TESTS_BUNDLE_MODEL_DIR= "model/kleisli";
private final static String SRC_MODELTYPE_NAME = "NECSIS14_DatabaseSchema";
private final static String SRC_METAMODEL_NAME = SRC_MODELTYPE_NAME + MMINT.MODEL_FILEEXTENSION_SEPARATOR + EcorePackage.eNAME;
private final static String SRC_MODELTYPEENDPOINT_NAME = "DB";
private final static String TGT_MODELTYPE_NAME = "NECSIS14_ClassDiagram";
private final static String TGT_METAMODEL_NAME = TGT_MODELTYPE_NAME + MMINT.MODEL_FILEEXTENSION_SEPARATOR + EcorePackage.eNAME;
private final static String TGT_MODELTYPEENDPOINT_NAME = "CD";
private final static String KLEISLI_MODELRELTYPE_URI = "http://se.cs.toronto.edu/modelepedia/KleisliModelRel";
private final static String MODELRELTYPE_NAME = TGT_MODELTYPEENDPOINT_NAME + MMINT.BINARY_MODELREL_MAPPING_SEPARATOR + SRC_MODELTYPEENDPOINT_NAME;
private final static String KLEISLI_TGT_METAMODEL_NAME = TGT_MODELTYPEENDPOINT_NAME + MMINT.ENDPOINT_SEPARATOR + TGT_MODELTYPE_NAME + MMINT.MODEL_FILEEXTENSION_SEPARATOR + EcorePackage.eNAME;
private final static String[] SRC_METAMODELOBJ_NAMES = {
"DatabaseSchema",
"NamedElement/name",
"Table",
"DatabaseSchema/tables",
"Column",
"Table/columns",
"Table/primaryKeys"
};
private final static String[] TGT_METAMODELOBJ_NAMES = {
"ClassDiagram",
"NamedElement/name",
"_QTable",
"ClassDiagram/_Qtables",
"_QColumn",
"_QTable/_Qcolumns",
"_QTable/_QprimaryKeys"
};
private final static String TGT_MODELELEM_QUERYLANGUAGE = "KLEISLI";
private final static String[] TGT_MODELELEM_OCLQUERIES = {
null,
null,
"union classes := classes\nunion associations := associations->select(upperBound > 1 or upperBound = -1)",
"origin.oclContainer()\norigin.oclContainer()",
"union classes := classes\nunion subclasses := classes->select(not parent.oclIsUndefined())\nunion attributes := classes->collect(attributes)\nunion multiAssociations1 := associations->select(upperBound > 1 or upperBound = -1)\nunion multiAssociations2 := associations->select(upperBound > 1 or upperBound = -1)\nunion singleAssociations := associations->select(upperBound = 1)",
"_QTable.classes->get(origin)\n_QTable.classes->get(origin.parent)\n_QTable.classes->get(origin.oclContainer())\n_QTable.associations->get(origin)\n_QTable.associations->get(origin)\n_QTable.classes->get(origin.target)",
"_QTable.classes->get(origin)\nNULL\nNULL\n_QTable.associations->get(origin)\n_QTable.associations->get(origin)\nNULL"
};
private final static String TESTS_TEMPPROJECT = TESTS_BUNDLE_NAME;
private final static String TESTS_TEMP_PROJECT_URI = IPath.SEPARATOR + TESTS_TEMPPROJECT + IPath.SEPARATOR;
private final static String TESTS_INSTANCEMID_URI = TESTS_TEMP_PROJECT_URI + "instances" + MMINT.MODEL_FILEEXTENSION_SEPARATOR + MIDPackage.eNAME;
private final static String INPUT_MODEL_FILENAME = "cd" + MMINT.MODEL_FILEEXTENSION_SEPARATOR + MIDTypeFactory.ECORE_REFLECTIVE_FILE_EXTENSION;
private final static String INPUT_MODEL_URI = TESTS_TEMP_PROJECT_URI + INPUT_MODEL_FILENAME;
private final static String OUTPUT_ORACLE_FILENAME = "cd_transformed" + MMINT.MODEL_FILEEXTENSION_SEPARATOR + MIDTypeFactory.ECORE_REFLECTIVE_FILE_EXTENSION;
private final static String OUTPUT_ORACLE_URI = TESTS_TEMP_PROJECT_URI + "oracle_" + OUTPUT_ORACLE_FILENAME;
private final static String SCHEMALOCATION_PLACEHOLDER = "SCHEMALOCATION";
private final static String KLEISLI_TRANSFORMATIONOPERATORTYPE_URI = "http://se.cs.toronto.edu/modelepedia/Operator_KleisliModelRelTypeTransformation";
private ModelElementReference dropMetamodelObject(EPackage metamodelRootObj, String metamodelObjName, ModelEndpointReference containerModelTypeEndpointRef, ModelElement rootModelElemType) throws MMINTException {
String[] names = metamodelObjName.split(MMINT.URI_SEPARATOR);
EObject metamodelObj;
if (names.length == 1) {
metamodelObj = metamodelRootObj.getEClassifier(names[0]);
}
else {
EClass metamodelObjContainer = (EClass) metamodelRootObj.getEClassifier(names[0]);
metamodelObj = metamodelObjContainer.getEStructuralFeature(names[1]);
}
Assert.assertTrue(containerModelTypeEndpointRef.acceptModelElementType(metamodelObj));
String modelElemTypeUri = MIDRegistry.getModelAndModelElementUris(metamodelObj, MIDLevel.TYPES)[1];
EMFInfo eInfo = MIDRegistry.getModelElementEMFInfo(metamodelObj, MIDLevel.TYPES);
String newModelElemTypeName = MIDRegistry.getModelElementName(eInfo, metamodelObj, MIDLevel.TYPES);
ModelElementReference newModelElemTypeRef = rootModelElemType.createSubtypeAndReference(null, modelElemTypeUri, newModelElemTypeName, eInfo, containerModelTypeEndpointRef);
MMINT.createTypeHierarchy();
return newModelElemTypeRef;
}
@Test
public void necsis14() throws Exception {
Bundle testBundle = Platform.getBundle(TESTS_BUNDLE_NAME);
// model types
Model rootModelType = MIDTypeRegistry.getType(MMINT.ROOT_MODEL_URI);
Model srcModelType = rootModelType.createSubtype(SRC_MODELTYPE_NAME, true);
MMINT.createTypeHierarchy();
URL srcMetamodelUrl = testBundle.findEntries(TESTS_BUNDLE_MODEL_DIR, SRC_METAMODEL_NAME, false).nextElement();
Files.copy(Paths.get(FileLocator.toFileURL(srcMetamodelUrl).getFile()), Paths.get(FileUtils.prependStatePathToUri(SRC_METAMODEL_NAME)), StandardCopyOption.REPLACE_EXISTING);
Model tgtModelType = rootModelType.createSubtype(TGT_MODELTYPE_NAME, true);
MMINT.createTypeHierarchy();
URL tgtMetamodelUrl = testBundle.findEntries(TESTS_BUNDLE_MODEL_DIR, TGT_METAMODEL_NAME, false).nextElement();
Files.copy(Paths.get(FileLocator.toFileURL(tgtMetamodelUrl).getFile()), Paths.get(FileUtils.prependStatePathToUri(TGT_METAMODEL_NAME)), StandardCopyOption.REPLACE_EXISTING);
// model rel type
KleisliModelRel kRootModelRelType = MIDTypeRegistry.getType(KLEISLI_MODELRELTYPE_URI);
KleisliModelRel kModelRelType = (KleisliModelRel) kRootModelRelType.createSubtype(MODELRELTYPE_NAME, false);
MMINT.createTypeHierarchy();
KleisliModelEndpoint kRootModelTypeEndpoint = (KleisliModelEndpoint) kRootModelRelType.getModelEndpoints().get(0);
ModelEndpointReference srcModelTypeEndpointRef = kRootModelTypeEndpoint.createSubtype(SRC_MODELTYPEENDPOINT_NAME, srcModelType, false, kModelRelType);
URL kTgtMetamodelUrl = testBundle.findEntries(TESTS_BUNDLE_MODEL_DIR, KLEISLI_TGT_METAMODEL_NAME, false).nextElement();
Files.copy(Paths.get(FileLocator.toFileURL(kTgtMetamodelUrl).getFile()), Paths.get(FileUtils.prependStatePathToUri(MODELRELTYPE_NAME + MMINT.URI_SEPARATOR + KLEISLI_TGT_METAMODEL_NAME)), StandardCopyOption.REPLACE_EXISTING);
KleisliModelEndpointReference kTgtModelTypeEndpointRef = (KleisliModelEndpointReference) kRootModelTypeEndpoint.createSubtype(TGT_MODELTYPEENDPOINT_NAME, tgtModelType, false, kModelRelType);
// model element types and link types
EPackage srcMetamodelRootObj = srcModelType.getEMFTypeRoot();
EPackage kTgtMetamodelRootObj = ((KleisliModelEndpoint) kTgtModelTypeEndpointRef.getObject()).getExtendedTarget().getEMFTypeRoot();
ModelElement rootModelElemType = MIDTypeHierarchy.getRootModelElementType();
Mapping rootMappingType = MIDTypeHierarchy.getRootMappingType();
ModelElementEndpoint rootModelElemTypeEndpoint = MIDTypeHierarchy.getRootModelElementTypeEndpoint();
for (int i = 0; i < SRC_METAMODELOBJ_NAMES.length; i++) {
ModelElementReference srcModelElemTypeRef = dropMetamodelObject(srcMetamodelRootObj, SRC_METAMODELOBJ_NAMES[i], srcModelTypeEndpointRef, rootModelElemType);
ModelElementReference tgtModelElemTypeRef = dropMetamodelObject(kTgtMetamodelRootObj, TGT_METAMODELOBJ_NAMES[i], kTgtModelTypeEndpointRef, rootModelElemType);
if (TGT_MODELELEM_OCLQUERIES[i] != null) {
ExtendibleElementConstraint constraint = MIDFactory.eINSTANCE.createExtendibleElementConstraint();
constraint.setLanguage(TGT_MODELELEM_QUERYLANGUAGE);
constraint.setImplementation(TGT_MODELELEM_OCLQUERIES[i]);
tgtModelElemTypeRef.getObject().setConstraint(constraint);
}
String newLinkTypeName = srcModelElemTypeRef.getObject().getName() + MMINT.BINARY_MODELREL_MAPPING_SEPARATOR + tgtModelElemTypeRef.getObject().getName();
MappingReference mappingTypeRef = rootMappingType.createSubtypeAndReference(null, newLinkTypeName, true, kModelRelType);
MMINT.createTypeHierarchy();
String srcModelElemTypeEndpointName = srcModelElemTypeRef.getObject().getName(), tgtModelElemTypeEndpointName = tgtModelElemTypeRef.getObject().getName();
if (srcModelElemTypeEndpointName.equals(tgtModelElemTypeEndpointName)) {
srcModelElemTypeEndpointName += srcModelTypeEndpointRef.getObject().getName();
tgtModelElemTypeEndpointName += kTgtModelTypeEndpointRef.getObject().getName();
}
rootModelElemTypeEndpoint.createSubtypeAndReference(srcModelElemTypeEndpointName, srcModelElemTypeRef, false, mappingTypeRef);
rootModelElemTypeEndpoint.createSubtypeAndReference(tgtModelElemTypeEndpointName, tgtModelElemTypeRef, false, mappingTypeRef);
}
// instances
createTestProject();
MID instanceMID = MIDFactory.eINSTANCE.createMID();
URL inputModelUrl = testBundle.findEntries(TESTS_BUNDLE_MODEL_DIR, INPUT_MODEL_FILENAME, false).nextElement();
FileUtils.copyTextFileAndReplaceText(
FileLocator.toFileURL(inputModelUrl).getFile().toString(),
FileUtils.prependWorkspacePathToUri(INPUT_MODEL_URI),
SCHEMALOCATION_PLACEHOLDER,
"file:" + FileUtils.prependStatePathToUri(TGT_METAMODEL_NAME),
false
);
Model inputModel = tgtModelType.createInstanceAndEditor(INPUT_MODEL_URI, instanceMID);
FileUtils.writeModelFile(instanceMID, TESTS_INSTANCEMID_URI, true); // this is needed for correct uris in the operator
Operator transformationOperator = MIDTypeRegistry.<Operator>getType(KLEISLI_TRANSFORMATIONOPERATORTYPE_URI);
EList<Model> transformationInputModels = new BasicEList<Model>();
transformationInputModels.add(inputModel);
EList<OperatorInput> transformationInputs = transformationOperator.checkAllowedInputs(transformationInputModels);
EList<OperatorGeneric> transformationGenerics = new BasicEList<>();
OperatorGeneric transformationGeneric = OperatorFactory.eINSTANCE.createOperatorGeneric();
transformationGeneric.setGenericSuperTypeEndpoint(transformationOperator.getGenerics().get(0));
transformationGeneric.setGeneric(kModelRelType);
transformationGenerics.add(transformationGeneric);
Map<String, MID> outputMIDsByName = MIDOperatorIOUtils.createSimpleOutputMIDsByName(transformationOperator, instanceMID);
Map<String, Model> transformationOutput = transformationOperator.startInstance(transformationInputs, null, transformationGenerics, outputMIDsByName, instanceMID).getOutputsByName();
FileUtils.writeModelFile(instanceMID, TESTS_INSTANCEMID_URI, true);
// test equivalence with oracle
ResourceSet oracleResourceSet = new ResourceSetImpl();
URI oracleResourceUri = URI.createPlatformPluginURI(TESTS_BUNDLE_NAME + IPath.SEPARATOR + TESTS_BUNDLE_MODEL_DIR + IPath.SEPARATOR + FileUtils.getLastSegmentFromUri(TESTS_INSTANCEMID_URI), true);
oracleResourceSet.getResource(oracleResourceUri, true);
ResourceSet outputResourceSet = new ResourceSetImpl();
outputResourceSet.getResource(URI.createPlatformResourceURI(TESTS_INSTANCEMID_URI, true), true);
IComparisonScope scope = new DefaultComparisonScope(oracleResourceSet, outputResourceSet, null);
Comparison comparison = EMFCompare.builder().build().compare(scope);
Assert.assertTrue(comparison.getDifferences().isEmpty());
URL outputModelUrl = testBundle.findEntries(TESTS_BUNDLE_MODEL_DIR, OUTPUT_ORACLE_FILENAME, false).nextElement();
FileUtils.copyTextFileAndReplaceText(
FileLocator.toFileURL(outputModelUrl).getFile().toString(),
FileUtils.prependWorkspacePathToUri(OUTPUT_ORACLE_URI),
SCHEMALOCATION_PLACEHOLDER,
"file:" + FileUtils.prependStatePathToUri(SRC_METAMODEL_NAME),
false
);
oracleResourceSet = new ResourceSetImpl();
oracleResourceUri = URI.createPlatformResourceURI(OUTPUT_ORACLE_URI, true);
oracleResourceSet.getResource(oracleResourceUri, true);
outputResourceSet = new ResourceSetImpl();
outputResourceSet.getResource(URI.createPlatformResourceURI(transformationOutput.get(0).getUri(), true), true);
scope = new DefaultComparisonScope(oracleResourceSet, outputResourceSet, null);
comparison = EMFCompare.builder().build().compare(scope);
Assert.assertTrue(comparison.getDifferences().isEmpty());
}
}