/*******************************************************************************
* Copyright (c) 2015 QNX Software Systems and others
* 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:
* Alena Laskavaia - Initial API and Implementation
*******************************************************************************/
package org.eclipse.linuxtools.valgrind.core.tests;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.junit.Assert;
import org.osgi.framework.Bundle;
/**
* Utilities for reading test source code from plug-in .java sources
*/
public class TestSourceReader {
private final Bundle bundle;
private final String srcRoot;
private final Class<?> clazz;
private final int numSections;
/**
* @param bundle
* the bundle containing the source, if {@code null} can try to load using classpath (source folder has
* to be in the classpath for this to work)
* @param srcRoot
* the directory inside the bundle containing the packages
* @param clazz
* the name of the class containing the test
*/
public TestSourceReader(Bundle bundle, String srcRoot, Class<?> clazz) {
this(bundle, srcRoot, clazz, 0);
}
/**
* @param bundle
* the bundle containing the source, if {@code null} can try to load using classpath (source folder has
* to be in the classpath for this to work)
* @param srcRoot
* the directory inside the bundle containing the packages
* @param clazz
* the name of the class containing the test
* @param numSections
* the number of comment sections preceding the named test to return. Pass zero to get all available
* sections.
*/
public TestSourceReader(Bundle bundle, String srcRoot, Class<?> clazz, int numSections) {
this.bundle = bundle;
this.srcRoot = srcRoot;
this.clazz = clazz;
this.numSections = numSections;
}
public StringBuilder[] getContentsForTest(final String testName) throws IOException {
return getContentsForTest(bundle, srcRoot, clazz, testName, numSections);
}
/**
* Returns an array of StringBuilder objects for each comment section found preceding the named test in the source
* code.
*
* @param bundle
* the bundle containing the source, if {@code null} can try to load using classpath (source folder has
* to be in the classpath for this to work)
* @param srcRoot
* the directory inside the bundle containing the packages
* @param clazz
* the name of the class containing the test
* @param testName
* the name of the test
* @param numSections
* the number of comment sections preceding the named test to return. Pass zero to get all available
* sections.
* @return an array of StringBuilder objects for each comment section found preceding the named test in the source
* code.
* @throws IOException if a source file is not found
*/
public static StringBuilder[] getContentsForTest(Bundle bundle, String srcRoot, Class<?> clazz, final String testName,
int numSections) throws IOException {
// Walk up the class inheritance chain until we find the test method.
try {
while (clazz.getMethod(testName).getDeclaringClass() != clazz) {
clazz = clazz.getSuperclass();
}
} catch (SecurityException e) {
Assert.fail(e.getMessage());
} catch (NoSuchMethodException e) {
Assert.fail(e.getMessage());
}
while (true) {
// Find and open the .java file for the class clazz.
String fqn = clazz.getName().replace('.', '/');
fqn = fqn.indexOf("$") == -1 ? fqn : fqn.substring(0, fqn.indexOf("$"));
String classFile = fqn + ".java";
IPath filePath = new Path(srcRoot + '/' + classFile);
InputStream in;
Class<?> superclass = clazz.getSuperclass();
try {
if (bundle != null) {
in = FileLocator.openStream(bundle, filePath, false);
} else {
in = clazz.getResourceAsStream('/' + classFile);
}
} catch (IOException e) {
if (superclass == null || !superclass.getPackage().equals(clazz.getPackage())) {
throw e;
}
clazz = superclass;
continue;
}
try (BufferedReader br = new BufferedReader(new InputStreamReader(in))) {
// Read the java file collecting comments until we encounter the test method.
List<StringBuilder> contents = new ArrayList<>();
StringBuilder content = new StringBuilder();
for (String line = br.readLine(); line != null; line = br.readLine()) {
line = line.replaceFirst("^\\s*", ""); // Replace leading whitespace, preserve trailing
if (line.startsWith("//")) {
content.append(line.substring(2) + "\n");
} else {
if (!line.startsWith("@") && content.length() > 0) {
contents.add(content);
if (numSections > 0 && contents.size() == numSections + 1)
contents.remove(0);
content = new StringBuilder();
}
if (line.length() > 0 && !contents.isEmpty()) {
int idx = line.indexOf(testName);
if (idx != -1 && !Character.isJavaIdentifierPart(line.charAt(idx + testName.length()))) {
return contents.toArray(new StringBuilder[contents.size()]);
}
if (!line.startsWith("@")) {
contents.clear();
}
}
}
}
}
if (superclass == null || !superclass.getPackage().equals(clazz.getPackage())) {
throw new IOException("Test data not found for " + clazz.getName() + "." + testName);
}
clazz = superclass;
}
}
}