/*******************************************************************************
* Copyright (c) 2006-2013
* 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.emftext.language.java.test.resolving_new;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.eclipse.core.runtime.CoreException;
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.EStructuralFeature;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.emftext.language.java.commons.Commentable;
import org.emftext.language.java.modifiers.AnnotationInstanceOrModifier;
import org.emftext.language.java.test.AbstractJavaParserTestCase;
/**
* A test for the reference resolving mechanism. Each folder
* contained INPUT_FOLDER is treated as a Java project and
* parsed into one ResourceSet. Afterwards all references are
* resolved and the annotations contained as comments in the
* input files are checked.
*/
public class ResolvingTest extends TestCase {
private static final String INPUT_FOLDER = "src-input" + File.separator + "resolving_new";
/**
* A FileFilter that does not accept SVN metadata directories.
*/
private static class IgnoreSVNFilter implements FileFilter {
public boolean accept(File file) {
if (file.getName().equals(".svn")) {
// ignore subversion directories
return false;
}
return true;
}
}
public static Test suite() throws CoreException {
TestSuite suite = new TestSuite();
File inputFolder = new File(INPUT_FOLDER);
// iterate over all folders in the input folder
File[] testDirectories = inputFolder.listFiles(new IgnoreSVNFilter());
for (final File nextDirectory : testDirectories) {
suite.addTest(new TestCase(nextDirectory.getName()) {
@Override
public void runTest() throws Throwable {
new DirectoryTest(nextDirectory).runTest();
}
});
}
return suite;
}
/**
* A test that is instantiated for a single directory. It collects all
* the files in the directory to build a classpath.
*/
private static class DirectoryTest extends AbstractJavaParserTestCase {
private File directory;
public DirectoryTest(File directory) {
super();
this.directory = directory;
}
public void runTest() {
testDirectory(directory);
}
private void testDirectory(File testDirectory) {
String directoryName = testDirectory.getName();
String[] parts = directoryName.split("_");
assertEquals("The directory name should contain two parts separated by an underscore.", 2, parts.length);
String expectedTargetString = parts[1];
int size;
try {
size = Integer.parseInt(expectedTargetString);
} catch (NumberFormatException nfe) {
fail("Can't parse expected number of targets in directory name.");
return;
}
// collect all java files and parse them into one
// resource set
ResourceSet set = new ResourceSetImpl();
set.getLoadOptions().putAll(getLoadOptions());
parseAll(testDirectory, set);
// resolve all references
EcoreUtil.resolveAll(set);
// find all commented EObjects that are sources or targets
Map<String, Object> actualTargetsMap = new HashMap<String, Object>();
Map<String, Object> expectedTargetsMap = new HashMap<String, Object>();
findSourcesAndTargets(set, actualTargetsMap, expectedTargetsMap);
// check whether the actual targets match the expected targets
for (String actualID : actualTargetsMap.keySet()) {
Object actualTarget = actualTargetsMap.get(actualID);
Object expectedTarget = expectedTargetsMap.get(actualID);
assertEquals("Target objects should match (ID " + actualID + ").", expectedTarget, actualTarget);
}
assertEquals("Number of expected and actual targets should match.", actualTargetsMap.keySet().size(), expectedTargetsMap.keySet().size());
// check whether the expected number of targets is present
assertEquals("Number of targets should match the expected number.", actualTargetsMap.keySet().size(), size);
}
private void findSourcesAndTargets(ResourceSet set,
Map<String, Object> actualTargetsMap,
Map<String, Object> expectedTargetsMap) {
List<Resource> resources = set.getResources();
for (Resource resource : resources) {
TreeIterator<EObject> contentIterator = resource.getAllContents();
while (contentIterator.hasNext()) {
EObject next = contentIterator.next();
if (next instanceof Commentable && !(next instanceof AnnotationInstanceOrModifier)) {
Commentable commentable = (Commentable) next;
List<String> commentList = commentable.getComments();
String comments = collapse(commentList);
if (comments.length() > 0) {
if (comments.contains("source:")) {
String[] parts = comments.split(":");
assertEquals("Expected three parts in comment separated by double colon (source:<id>:nameOfReference).", 3, parts.length);
String id = parts[1].replace('\n', ' ').replace('\r', ' ').trim();
String referenceName = parts[2].replace('\n', ' ').replace('\r', ' ').trim();
Object target = getTarget(commentable, referenceName);
assertNotNull(target);
actualTargetsMap.put(id, target);
}
if (comments.contains("target:")) {
String[] parts = comments.split(":");
assertEquals("Expected two parts in comment ("+comments+") separated by double colon (target:<id>).", 2, parts.length);
String id = parts[1].replace('\n', ' ').replace('\r', ' ').trim();
expectedTargetsMap.put(id, commentable);
}
}
}
}
}
}
private Object getTarget(Commentable commentable, String referenceName) {
String[] references = referenceName.split("\\.");
EObject target = commentable;
for (String reference : references) {
if ("eContainer".equals(reference)) {
target = target.eContainer();
assertNotNull("Found null container.", target);
} else {
EStructuralFeature feature = target.eClass().getEStructuralFeature(reference);
assertNotNull("Can't find feature \"" + reference + "\"", feature);
target = (EObject) target.eGet(feature);
}
}
return target;
}
private String collapse(List<String> commentList) {
StringBuilder sb = new StringBuilder();
for (String comment : commentList) {
sb.append(comment);
//only the first comment
break;
}
return sb.toString();
}
private void parseAll(File testDirectory, ResourceSet set) {
File[] files = testDirectory.listFiles(new IgnoreSVNFilter());
for (File file : files) {
if (file.isDirectory()) {
parseAll(file, set);
} else if (file.getName().endsWith(".java")) {
// parse file into resource set
URI uri = URI.createFileURI(file.getAbsolutePath());
Resource resource = set.createResource(uri);
try {
resource.load(getLoadOptions());
} catch (IOException e) {
fail(e.getMessage());
}
} else {
fail("Found unexpected unknown file " + file.getAbsolutePath());
}
}
}
@Override
protected String getTestInputFolder() {
return INPUT_FOLDER;
}
@Override
protected boolean isExcludedFromReprintTest(String filename) {
return true;
}
}
}