/*******************************************************************************
* Copyright (c) 2006-2012
* Software Technology Group, Dresden University of Technology
* DevBoost GmbH, Berlin, Amtsgericht Charlottenburg, HRB 140026
*
* 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:
* Software Technology Group - TU Dresden, Germany;
* DevBoost GmbH - Berlin, Germany
* - initial API and implementation
******************************************************************************/
package org.reuseware.coconut.test;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import static org.junit.Assert.*;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.compare.diff.metamodel.AttributeChange;
import org.eclipse.emf.compare.diff.metamodel.DiffGroup;
import org.eclipse.emf.compare.diff.metamodel.DiffModel;
import org.eclipse.emf.compare.diff.metamodel.ReferenceChange;
import org.eclipse.emf.compare.diff.metamodel.ReferenceChangeLeftTarget;
import org.eclipse.emf.compare.diff.metamodel.ReferenceChangeRightTarget;
import org.eclipse.emf.compare.diff.metamodel.ReferenceOrderChange;
import org.eclipse.emf.compare.diff.service.DiffService;
import org.eclipse.emf.compare.match.MatchOptions;
import org.eclipse.emf.compare.match.metamodel.MatchModel;
import org.eclipse.emf.compare.match.service.MatchService;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceImpl;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;
import org.junit.After;
import org.junit.Before;
import org.reuseware.coconut.compositionprogram.CompositionLink;
import org.reuseware.coconut.compositionprogram.CompositionProgram;
import org.reuseware.coconut.compositionprogram.CompositionprogramPackage;
import org.reuseware.coconut.compositionprogram.FragmentInstance;
import org.reuseware.coconut.compositionprogram.resource.UCLResourceFactory;
import org.reuseware.coconut.fracol.resource.fracol.mopp.FracolResourceFactory;
import org.reuseware.coconut.fragment.Fragment;
import org.reuseware.coconut.fragment.PhysicalFragment;
import org.reuseware.coconut.resource.ReuseResources;
import org.reuseware.coconut.resource.util.ReuseResourcesUtil;
import org.reuseware.coconut.reuseextension.evaluator.EvaluatorUtil;
import org.reuseware.coconut.reuseextension.evaluator.ocl.EnhancedOCLEvaluator;
import org.reuseware.coconut.reuseextension.evaluator.ocl.PlainOCLEvaluator;
import org.reuseware.coconut.reuseextension.resource.rex.mopp.RexResourceFactory;
import org.reuseware.coconut.reuseextensionactivator.resource.rexactivator.mopp.Rex_activatorResourceFactory;
public abstract class AbstractReusewareCompositionTestCase {
public static final String TEMP_STORE_URI = "out";
public Map<?,?> getLoadOptions() {
return Collections.emptyMap();
}
abstract public AbstractReusewareTestHelper getTestHelper();
protected AbstractReusewareTestHelper testHelper = null;
protected ReuseResources reuseResources = ReuseResources.INSTANCE;
protected boolean doOutput = true;
protected ResourceSet resourceSet = null;
protected void assertRegisterFragmentStore(String exampleID, String folder, String[] fileExtensions, boolean allowErrorsInRexActivators) throws Exception {
testHelper.addStore(exampleID, folder, fileExtensions, allowErrorsInRexActivators);
update();
}
protected void assertRegisterFragmentStore(String exampleID, String folder, String[] fileExtensions) throws Exception {
testHelper.addStore(exampleID, folder, fileExtensions, false);
update();
}
protected void assertFragmentExists(List<String> UFI) {
ResourceSet tempResourceSet = resourceSet;
Fragment fragment = reuseResources.getFragment(UFI, tempResourceSet);
assertTrue("Fragment '" + UFI + "' does not exist",
fragment != null);
}
protected Fragment getFragment(String[] ufiArray) {
List<String> UFI = Arrays.asList(ufiArray);
ResourceSet tempResourceSet = resourceSet;
Fragment fragment = reuseResources.getFragment(UFI, tempResourceSet);
assertTrue("Fragment '" + UFI + "' does not exist",
fragment != null);
return fragment;
}
protected CompositionProgram getCompositionProgram(String[] ufiArray) {
List<String> UCPI = Arrays.asList(ufiArray);
ResourceSet tempResourceSet = resourceSet;
CompositionProgram compositionProgram = ReuseResourcesUtil.getCompositionProgram(UCPI, tempResourceSet);
assertTrue("Composition program '" + UCPI + "' does not exist",
compositionProgram != null);
for(FragmentInstance fi : compositionProgram.getFragmentInstances()) {
assertFragmentInstanceValid(fi);
}
boolean result = true;
for(CompositionLink link : compositionProgram.getCompositionLinks()) {
link.match();
result = result && isLinkValid(link);
}
assertTrue("Invalid links in " + compositionProgram.getUCPI(), result);
return compositionProgram;
}
protected void assertNotFragmentExists(String[] ufiArray) {
List<String> UFI = Arrays.asList(ufiArray);
ResourceSet tempResourceSet = resourceSet;
Fragment fragment = reuseResources.getFragment(UFI, tempResourceSet);
assertFalse("Fragment '" + UFI + "' does not exist",
fragment instanceof PhysicalFragment);
}
protected boolean isLinkValid(CompositionLink link) {
if(!link.isValid()) {
System.out.println(" Can not match: " +
link.getSource().getFragmentRoleName() + "." + link.getSource().getPortName() + " ----> " +
link.getTarget().getFragmentRoleName() + "." + link.getTarget().getPortName());
return false;
}
if(link.isEmpty()) {
System.out.println(" Empty link: " +
link.getSource().getFragmentRoleName() + "." + link.getSource().getPortName() + " ----> " +
link.getTarget().getFragmentRoleName() + "." + link.getTarget().getPortName());
return false;
}
System.out.println(" Link ok: "
+ link.getSource().getFragmentRoleName() + "."
+ link.getSource().getPortName() + " ----> "
+ link.getTarget().getFragmentRoleName() + "."
+ link.getTarget().getPortName());
return true;
}
protected void assertFragmentInstanceValid(FragmentInstance fragmentInst) {
assertNotNull("Fragment " + fragmentInst.getUFI() +
" not registered but used in cp", fragmentInst.getFragment());
}
protected void assertFragmentsEqual(List<String> UFI1, List<String> UFI2, String[] attributesToIgnore) throws InterruptedException {
ResourceSet tempResourceSet = resourceSet;
assertFragmentExists(UFI1);
Fragment fragment1 = reuseResources.getFragment(UFI1, tempResourceSet);
assertFragmentExists(UFI2);
Fragment fragment2 = reuseResources.getFragment(UFI2, tempResourceSet);
assertFalse(UFI1 + " is empty", fragment1.getContents().isEmpty());
assertFalse(UFI2 + " is empty", fragment2.getContents().isEmpty());
// Compare reference with output
Map<String, Object> options = new HashMap<String, Object>();
options.put(MatchOptions.OPTION_IGNORE_XMI_ID, true);
options.put(MatchOptions.OPTION_IGNORE_ID, true);
Resource model1Resource = null;
for(EObject aRoot : fragment1.getContents()) {
if(model1Resource == null) {
model1Resource = aRoot.eResource();
continue;
}
if(model1Resource != aRoot.eResource()) {
//elements from different resources
model1Resource = null;
break;
}
}
Resource model2Resource = null;
for(EObject aRoot : fragment2.getContents()) {
if(model2Resource == null) {
model2Resource = aRoot.eResource();
continue;
}
if(model2Resource != aRoot.eResource()) {
model2Resource = null;
break;
}
}
//due to a bug in EMFCompare, each model needs to be in a resource
//+ EMFCompare needs a resource when a list should be compared
if (model1Resource == null) {
model1Resource = new ResourceImpl(URI.createURI("temp1.ecore"));
model1Resource.getContents().addAll(fragment1.getContents());
}
if (model2Resource == null) {
model2Resource = new ResourceImpl(URI.createURI("temp2.ecore"));
model2Resource.getContents().addAll(fragment2.getContents());
}
MatchModel inputMatch = MatchService.doResourceMatch(model1Resource,
model2Resource, options);
DiffModel inputDiff = DiffService.doDiff(inputMatch);
for(Iterator<EObject> diffIt = inputDiff.eAllContents(); diffIt.hasNext(); ) {
EObject localDiff = diffIt.next();
if (localDiff instanceof DiffGroup) {
continue;
}
if (localDiff instanceof ReferenceOrderChange) {
//ignore reference order changes
continue;
}
if (localDiff instanceof ReferenceChangeLeftTarget || localDiff instanceof ReferenceChangeRightTarget) {
if (((ReferenceChange) localDiff).getLeftElement() instanceof EAnnotation &&
((ReferenceChange) localDiff).getRightElement() instanceof EAnnotation) {
//in the 'ReuseUML' example there is a change in EAnnotation.references,
//although there is only one element in references
continue;
}
}
if (localDiff instanceof AttributeChange) {
if (Arrays.asList(attributesToIgnore).contains(
((AttributeChange)localDiff).getAttribute().getName())) {
continue;
}
}
System.err.println("Model diff:" + localDiff);
assertTrue(UFI1 + " and " + UFI2 + " are not equal. Check in DiffView.", false);
}
}
protected void assertCompositionCorrect(String[] IDArray, String[] referenceIDArray) throws InterruptedException {
assertCompositionCorrect(IDArray, referenceIDArray, new String[] {});
}
protected CompositionProgram getCompositionProgramForComposedFragment(List<String> composedUFI) {
CompositionProgram result = null;
for(List<String> UCPI : reuseResources.getAllCompositionProgramIDs()) {
ResourceSet tempResourceSet = newResourceSet();
CompositionProgram compositionProgram = ReuseResourcesUtil.getCompositionProgram(UCPI, tempResourceSet);
if (compositionProgram != null) {
for(FragmentInstance fi : compositionProgram.getFragmentInstances()) {
if (fi.isTarget() && composedUFI.equals(fi.getTargetUFI())) {
assertFragmentInstanceValid(fi);
assertNull(composedUFI + " is composed by more than one target fragment instances.", result);
result = compositionProgram;
}
}
}
}
return result;
}
protected void assertCompositionCorrect(String[] UFIArray, String[] referenceUFIArray, String[] attributesToIgnore) throws InterruptedException {
List<String> UFI = Arrays.asList(UFIArray);
List<String> referenceUFI = Arrays.asList(referenceUFIArray);
CompositionProgram compositionProgram = getCompositionProgramForComposedFragment(UFI);
assertNotNull(UFI + " is not a composed fragment.", compositionProgram);
for(FragmentInstance fragmentInst : compositionProgram.getFragmentInstances()) {
assertFragmentInstanceValid(fragmentInst);
}
System.out.println("Checking Composition Program: " + compositionProgram.getUCPI());
boolean result = true;
for(CompositionLink link : compositionProgram.getCompositionLinks()) {
link.match();
result = isLinkValid(link) && result;
}
assertTrue("Invalid links in " + compositionProgram.getUCPI(), result);
assertFragmentsEqual(UFI, referenceUFI, attributesToIgnore);
}
protected void updateArtifact(EObject elementInArtifact) throws IOException {
assertNotNull(elementInArtifact.eResource());
elementInArtifact.eResource().save(resourceSet.getLoadOptions());
testHelper.registerArtifact(elementInArtifact.eResource().getURI());
}
protected void update() {
testHelper.update();
}
protected ResourceSet newResourceSet() {
ResourceSet resourceSet = new ResourceSetImpl();
EPackage.Registry.INSTANCE.put(
CompositionprogramPackage.eNS_URI, CompositionprogramPackage.eINSTANCE);
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(
Resource.Factory.Registry.DEFAULT_EXTENSION, new XMIResourceFactoryImpl());
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(
"ecore", new EcoreResourceFactoryImpl());
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(
"fracol", new FracolResourceFactory());
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(
"rex", new RexResourceFactory());
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(
"rex_activator", new Rex_activatorResourceFactory());
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(
"ucl", new UCLResourceFactory());
resourceSet.getLoadOptions().putAll(getLoadOptions());
return resourceSet;
}
protected void assertFolderStructureContainedIn(
String project1ID, String folder1Name,
String project2ID, String folder2Name,
boolean ignoreLineOrder) throws Exception {
File folder1 = new File(".." + File.separator + project1ID + File.separator + folder1Name);
File folder2 = new File(".." + File.separator + project2ID + File.separator + folder2Name);
assertFolderStructureContainedIn(folder1, folder2, ignoreLineOrder);
}
protected void assertFolderStructureContainedIn(File containedFolder, File containingFolder, boolean ignoreLineOrder) throws Exception {
File[] containedFileList = containedFolder.listFiles();
File[] containingFileList = containingFolder.listFiles();
for (int i = 0; i < containedFileList.length; i++) {
File containedFile = containedFileList[i];
//do not check hidden files (e.g., .store)
if (containedFile.getName().startsWith(".")) {
continue;
}
boolean found = false;
for (int j = 0; j < containingFileList.length; j++) {
File containingFile = containingFileList[j];
if (containedFile.isDirectory() == containingFile.isDirectory()) {
if (containedFile.getName().equals(containingFile.getName())) {
found = true;
if (containedFile.isDirectory()) {
assertFolderStructureContainedIn(containedFile, containingFile, ignoreLineOrder);
}
else {
//compare file content
byte[] buffer1 = new byte[(int) containedFile.length()];
BufferedInputStream is1 = new BufferedInputStream(new FileInputStream(containedFile));
is1.read(buffer1);
byte[] buffer2 = new byte[(int) containingFile.length()];
BufferedInputStream is2 = new BufferedInputStream(new FileInputStream(containingFile));
is2.read(buffer2);
String s1 = new String(buffer1);
String s2 = new String(buffer2);
if (ignoreLineOrder) {
SortedSet<String> s1LineList = new TreeSet<String>(Arrays.asList(s1.split("\n")));
SortedSet<String> s2LineList = new TreeSet<String>(Arrays.asList(s2.split("\n")));
Iterator<String> s1Iterator = s1LineList.iterator();
Iterator<String> s2Iterator = s2LineList.iterator();
while (s1Iterator.hasNext() && s2Iterator.hasNext()) {
assertEquals("File content differs: " + containingFile.getName(), s1Iterator.next(), s2Iterator.next());
}
}
else {
//because in some exercises files get extended, we only compare
//the beginning of the file and cut the last character (which should be "}")
if (s1.length() < s2.length() ) {
s1 = s1.substring(0, s1.length() - 1);
s2 = s2.substring(0, s1.length());
}
assertEquals("File content differs: " + containingFile.getName(), s1, s2);
}
}
}
}
}
assertTrue("No equivalent file found: " + containedFile, found);
}
}
@Before
public void setUp() throws Exception {
testHelper = getTestHelper();
testHelper.setTest(this);
testHelper.initReuseResources(getLoadOptions());
EvaluatorUtil.addEvaluator(new EnhancedOCLEvaluator());
EvaluatorUtil.addEvaluator(new PlainOCLEvaluator());
resourceSet = newResourceSet();
}
@After
public void tearDown() throws Exception {
reuseResources.shutDown();
resourceSet = null;
testHelper = null;
}
public void setDoOutput(boolean doOutput) {
this.doOutput = doOutput;
}
}