Skip to content

Commit 6f990d0

Browse files
authored
fix the bug: Cannot run from src/test anymore bug #413 (#232)
* fix the bug: Cannot run from src/test anymore bug #375
1 parent e1a3505 commit 6f990d0

File tree

2 files changed

+99
-14
lines changed

2 files changed

+99
-14
lines changed

com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/JdtUtils.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
import org.eclipse.core.runtime.IPath;
2626
import org.eclipse.debug.core.sourcelookup.ISourceContainer;
2727
import org.eclipse.jdt.core.IClassFile;
28+
import org.eclipse.jdt.core.IClasspathAttribute;
29+
import org.eclipse.jdt.core.IClasspathEntry;
30+
import org.eclipse.jdt.core.IJavaElement;
2831
import org.eclipse.jdt.core.IJavaProject;
2932
import org.eclipse.jdt.core.IModuleDescription;
3033
import org.eclipse.jdt.core.IPackageFragmentRoot;
@@ -47,6 +50,9 @@
4750
import com.sun.jdi.Type;
4851

4952
public class JdtUtils {
53+
private static final String TEST_SCOPE = "test";
54+
private static final String MAVEN_SCOPE_ATTRIBUTE = "maven.scope";
55+
private static final String GRADLE_SCOPE_ATTRIBUTE = "gradle_scope";
5056

5157
/**
5258
* Returns the module this project represents or null if the Java project doesn't represent any named module.
@@ -117,6 +123,50 @@ public static IProject getProject(String projectName) {
117123
return root.getProject(projectName);
118124
}
119125

126+
/**
127+
* Compute the fragment roots for each test source folders.
128+
*
129+
* @param project the java project.
130+
* @return the fragment roots for each test source folders.
131+
*/
132+
public static IPackageFragmentRoot[] getTestPackageFragmentRoots(IJavaProject project) {
133+
try {
134+
IPackageFragmentRoot[] packageFragmentRoot = project.getPackageFragmentRoots();
135+
List<IPackageFragmentRoot> sources = new ArrayList<>();
136+
for (int i = 0; i < packageFragmentRoot.length; i++) {
137+
if (packageFragmentRoot[i].getElementType() == IJavaElement.PACKAGE_FRAGMENT_ROOT
138+
&& packageFragmentRoot[i].getKind() == IPackageFragmentRoot.K_SOURCE) {
139+
IClasspathEntry cpe = packageFragmentRoot[i].getResolvedClasspathEntry();
140+
141+
if (isTest(cpe)) {
142+
sources.add(packageFragmentRoot[i]);
143+
}
144+
}
145+
}
146+
return sources.toArray(new IPackageFragmentRoot[0]);
147+
} catch (JavaModelException e) {
148+
// ignore
149+
return new IPackageFragmentRoot[0];
150+
}
151+
}
152+
153+
/**
154+
* There is an issue on IClasspathEntry#isTest: it will return true if the scope is runtime, so we will this method for testing whether
155+
* the classpath entry is for test only.
156+
*
157+
* @param classpathEntry classpath entry
158+
* @return whether this classpath entry is only used in test
159+
*/
160+
public static boolean isTest(final IClasspathEntry classpathEntry) {
161+
for (IClasspathAttribute attribute : classpathEntry.getExtraAttributes()) {
162+
if (GRADLE_SCOPE_ATTRIBUTE.equals(attribute.getName()) || MAVEN_SCOPE_ATTRIBUTE.equals(attribute.getName())) {
163+
return TEST_SCOPE.equals(attribute.getValue());
164+
}
165+
}
166+
return classpathEntry.isTest();
167+
}
168+
169+
120170
/**
121171
* Compute the possible source containers that the specified project could be associated with.
122172
* <p>

com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/ResolveClasspathsHandler.java

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@
2222
import org.eclipse.core.runtime.CoreException;
2323
import org.eclipse.core.runtime.IStatus;
2424
import org.eclipse.core.runtime.Status;
25-
import org.eclipse.jdt.core.IClasspathAttribute;
26-
import org.eclipse.jdt.core.IClasspathEntry;
2725
import org.eclipse.jdt.core.IJavaElement;
2826
import org.eclipse.jdt.core.IJavaProject;
2927
import org.eclipse.jdt.core.search.IJavaSearchConstants;
@@ -40,7 +38,7 @@
4038

4139
public class ResolveClasspathsHandler {
4240
private static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME);
43-
private static final String SCOPE_ATTRIBUTE = "maven.scope";
41+
4442

4543
/**
4644
* Resolves class path for a java project.
@@ -150,7 +148,8 @@ private static String[][] computeClassPath(String mainClass, String projectName)
150148
}
151149
project = projects.get(0);
152150
}
153-
return computeClassPath(project);
151+
152+
return computeClassPath(project, isMainClassInTestFolder(project, mainClass));
154153
}
155154

156155
/**
@@ -162,31 +161,34 @@ private static String[][] computeClassPath(String mainClass, String projectName)
162161
* @throws CoreException
163162
* CoreException
164163
*/
165-
private static String[][] computeClassPath(IJavaProject javaProject) throws CoreException {
164+
private static String[][] computeClassPath(IJavaProject javaProject, boolean includeTestScope)
165+
throws CoreException {
166166
if (javaProject == null) {
167167
throw new IllegalArgumentException("javaProject is null");
168168
}
169169
String[][] result = new String[2][];
170170
if (JavaRuntime.isModularProject(javaProject)) {
171-
result[0] = computeDefaultRuntimeClassPath(javaProject);
171+
result[0] = computeDefaultRuntimeClassPath(javaProject, includeTestScope);
172172
result[1] = new String[0];
173173
} else {
174174
result[0] = new String[0];
175-
result[1] = computeDefaultRuntimeClassPath(javaProject);
175+
result[1] = computeDefaultRuntimeClassPath(javaProject, includeTestScope);
176176
}
177177
return result;
178178
}
179179

180-
private static String[] computeDefaultRuntimeClassPath(IJavaProject jproject) throws CoreException {
180+
private static String[] computeDefaultRuntimeClassPath(IJavaProject jproject, boolean includeTestScope)
181+
throws CoreException {
181182
IRuntimeClasspathEntry[] unresolved = JavaRuntime.computeUnresolvedRuntimeClasspath(jproject);
182183
Set<String> resolved = new LinkedHashSet<String>();
183184
for (int i = 0; i < unresolved.length; i++) {
184185
IRuntimeClasspathEntry entry = unresolved[i];
185186
if (entry.getClasspathProperty() == IRuntimeClasspathEntry.USER_CLASSES) {
186-
IRuntimeClasspathEntry[] entries = JavaRuntime.resolveRuntimeClasspathEntry(entry, jproject, true);
187+
IRuntimeClasspathEntry[] entries = JavaRuntime.resolveRuntimeClasspathEntry(entry, jproject,
188+
!includeTestScope);
187189
for (int j = 0; j < entries.length; j++) {
188190

189-
if (entries[j].getClasspathEntry().isTest() && !isRuntime(entries[j].getClasspathEntry())) {
191+
if (!includeTestScope && JdtUtils.isTest(entries[j].getClasspathEntry())) {
190192
continue;
191193
}
192194
String location = entries[j].getLocation();
@@ -200,10 +202,43 @@ private static String[] computeDefaultRuntimeClassPath(IJavaProject jproject) th
200202
return resolved.toArray(new String[resolved.size()]);
201203
}
202204

203-
private static boolean isRuntime(final IClasspathEntry classpathEntry) {
204-
for (IClasspathAttribute attribute : classpathEntry.getExtraAttributes()) {
205-
if (SCOPE_ATTRIBUTE.equals(attribute.getName()) && "runtime".equals(attribute.getValue())) {
206-
return true;
205+
206+
/**
207+
* Test whether the main class is located in test folders.
208+
* @param project the java project containing the main class
209+
* @param mainClass the main class name
210+
* @return whether the main class is located in test folders
211+
*/
212+
private static boolean isMainClassInTestFolder(IJavaProject project, String mainClass) {
213+
// get a list of test folders and check whether main class is here
214+
int constraints = IJavaSearchScope.SOURCES;
215+
IJavaElement[] testFolders = JdtUtils.getTestPackageFragmentRoots(project);
216+
if (testFolders.length > 0) {
217+
try {
218+
219+
List<Object> mainClassesInTestFolder = new ArrayList<>();
220+
SearchPattern pattern = SearchPattern.createPattern(mainClass, IJavaSearchConstants.CLASS,
221+
IJavaSearchConstants.DECLARATIONS,
222+
SearchPattern.R_CASE_SENSITIVE | SearchPattern.R_EXACT_MATCH);
223+
SearchEngine searchEngine = new SearchEngine();
224+
IJavaSearchScope scope = SearchEngine.createJavaSearchScope(testFolders, constraints);
225+
SearchRequestor requestor = new SearchRequestor() {
226+
@Override
227+
public void acceptSearchMatch(SearchMatch match) {
228+
Object element = match.getElement();
229+
if (element instanceof IJavaElement) {
230+
mainClassesInTestFolder.add(element);
231+
}
232+
}
233+
};
234+
235+
searchEngine.search(pattern, new SearchParticipant[] {
236+
SearchEngine.getDefaultSearchParticipant()
237+
}, scope, requestor, null /* progress monitor */);
238+
239+
return !mainClassesInTestFolder.isEmpty();
240+
} catch (Exception e) {
241+
logger.log(Level.SEVERE, String.format("Searching the main class failure: %s", e.toString()), e);
207242
}
208243
}
209244
return false;

0 commit comments

Comments
 (0)