Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1204,8 +1204,9 @@ private static FileObject findPath(
final StringBuilder relativePathBuilder = new StringBuilder();
FileObject child;
String separator = ""; //NOI18N
for (int i = 0; i < nameParts.length && parent != null; i += 2, parent = child) {
child = parent.getFileObject(nameParts[i], nameParts[i + 1]);
for (int i = 0; i < nameParts.length && parent != null; i += 2, parent = child) {
String classDefinedInFile = nameParts[i].split("\\$")[0];
child = parent.getFileObject(classDefinedInFile, nameParts[i + 1]);
if (child != null) {
relativePathBuilder.append(separator).append(child.getNameExt());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import org.netbeans.modules.parsing.spi.Parser;
import org.netbeans.spi.java.hints.unused.UsedDetector;
import org.netbeans.spi.project.SingleMethod;
import org.netbeans.spi.project.NestedClass;
import org.openide.filesystems.FileObject;
import org.openide.util.Exceptions;
import org.openide.util.lookup.ServiceProvider;
Expand Down Expand Up @@ -150,12 +151,13 @@ private static void collect(CompilationInfo info, TreePath clazz, List<TreePath>
int end = (int) sp.getEndPosition(tp.getCompilationUnit(), tp.getLeaf());
Document doc = info.getSnapshot().getSource().getDocument(false);
try {
NestedClass nestedClass = getNestedClass(elements.getBinaryName(typeElement).toString(), info.getFileObject());
result.add(new TestMethod(elements.getBinaryName(typeElement).toString(),
doc != null ? doc.createPosition(clazzPreferred) : new SimplePosition(clazzPreferred),
new SingleMethod(info.getFileObject(), mn),
doc != null ? doc.createPosition(start) : new SimplePosition(start),
doc != null ? doc.createPosition(preferred) : new SimplePosition(preferred),
doc != null ? doc.createPosition(end) : new SimplePosition(end)));
doc != null ? doc.createPosition(clazzPreferred) : new SimplePosition(clazzPreferred),
nestedClass != null ? new SingleMethod(mn, nestedClass) : new SingleMethod(info.getFileObject(), mn),
doc != null ? doc.createPosition(start) : new SimplePosition(start),
doc != null ? doc.createPosition(preferred) : new SimplePosition(preferred),
doc != null ? doc.createPosition(end) : new SimplePosition(end)));
} catch (BadLocationException ex) {
//ignore
}
Expand All @@ -178,6 +180,20 @@ private static void collect(CompilationInfo info, TreePath clazz, List<TreePath>
}
}

private static NestedClass getNestedClass(String fqClassName, FileObject fileObject) {
// drop the package name
String fileName = fileObject.getName();
String classOnly = fqClassName.substring(fqClassName.lastIndexOf('.') + 1);
if (classOnly.startsWith(fileName) && classOnly.length() > fileName.length()) {
int topLevelClassSeparatorIdx = classOnly.indexOf("$");
String topLevelClass = classOnly.substring(0,topLevelClassSeparatorIdx);
String nestedName = classOnly.substring(topLevelClassSeparatorIdx + 1);
NestedClass nestedClass = new NestedClass(nestedName, topLevelClass, fileObject);
return nestedClass;
}
return null;
Copy link
Member

@sdedic sdedic Jul 19, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: there may be multiple toplevel classes in a file: how is the SingleMethod supposed to capture that ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. How is it done today?

}

private static boolean isTestSource(FileObject fo) {
ClassPath cp = ClassPath.getClassPath(fo, ClassPath.SOURCE);
if (cp != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,16 @@ public void run(CompilationController compilationController) throws Exception {
compilationController.toPhase(Phase.ELEMENTS_RESOLVED);
Trees trees = compilationController.getTrees();
CompilationUnitTree compilationUnitTree = compilationController.getCompilationUnit();
String[] classHierarchy = classHierarchy(node.getTestcase().getClassName());
List<? extends Tree> typeDecls = compilationUnitTree.getTypeDecls();
for (Tree tree : typeDecls) {
Element element = trees.getElement(trees.getPath(compilationUnitTree, tree));
if (element != null && element.getKind() == ElementKind.CLASS && element.getSimpleName().contentEquals(fo2open[0].getName())) {
List<? extends ExecutableElement> methodElements = ElementFilter.methodsIn(element.getEnclosedElements());
Element classElement = getClassElement(element, classHierarchy, 0);
if (classElement == null) {
classElement = getClassElement(element, new String[] {fo2open[0].getName()}, 0);
}
if (classElement != null) {
List<? extends ExecutableElement> methodElements = ElementFilter.methodsIn(classElement.getEnclosedElements());
for (Element child : methodElements) {
String name = node.getTestcase().getName(); // package.name.method.name
if (child.getSimpleName().contentEquals(name.substring(name.lastIndexOf(".") + 1))) {
Expand All @@ -145,6 +150,40 @@ public void run(CompilationController compilationController) throws Exception {
}
}

private String[] classHierarchy(String testNodeClassName) {
String classNamesOnly = testNodeClassName;
// strip package names
int lastDot = testNodeClassName.lastIndexOf(".");
if (lastDot >= 0) {
classNamesOnly = classNamesOnly.substring(lastDot + 1);
}

// split embedded classes
return classNamesOnly.split("\\$");
}

Element getClassElement(Element element, String[] classHierarchy, int depth) {
if (element == null || element.getKind() != ElementKind.CLASS || depth >= classHierarchy.length) {
return null;
}

if (!element.getSimpleName().contentEquals(classHierarchy[depth])) {
return null;
}

if (depth + 1 == classHierarchy.length) {
return element;
}

for (Element enclosedElement : element.getEnclosedElements()) {
Element enclosedClass = getClassElement(enclosedElement, classHierarchy, depth + 1);
if (enclosedClass != null) {
return enclosedClass;
}
}
return null;
}

public void openCallstackFrame(Node node, @NonNull String frameInfo) {
if(frameInfo.isEmpty()) { // user probably clicked on a failed test method node, find failing line within the testMethod using the stacktrace
if (!(node instanceof JUnitTestMethodNode)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,13 @@ private void generateTest() {
}
}

String classname = testcase.getAttributeValue("classname");
// keep the embedded class in classnames and add to display name
int suiteNameLength = suite.getName().length();
if (classname.length() > suiteNameLength && classname.startsWith(suite.getName())) {
displayName = classname.substring(suiteNameLength) + "." + methodName;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: when is this code path executed ? I have tried running the whole testsuite, and a single method within a nested class, but did not hit the branch. I am asking bcs it seems as there should be '.' or '$' at suiteNameLength-th character, so '.' would be duplicated.

Copy link
Contributor Author

@ratcashdev ratcashdev Sep 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you tried using the @Nested JUnit5 annotation?

class MyClassTest {

  @Nested
  class NestedGroupTest {
    @Test
    public void mytest() {...}
  }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it should look like this:
image

}

Testcase test = new JUnitTestcase(methodName, displayName, testType, session);
Element stdout = testcase.getChild("system-out"); //NOI18N
// If *-output.txt file exists do not log standard output here to avoid logging it twice.
Expand Down Expand Up @@ -811,7 +818,6 @@ private void generateTest() {
float fl = NumberFormat.getNumberInstance(Locale.ENGLISH).parse(time).floatValue();
test.setTimeMillis((long)(fl * 1000));
}
String classname = testcase.getAttributeValue("classname");
if (classname != null) {
//#204480
if (classname.endsWith(nameSuffix)) {
Expand Down
23 changes: 19 additions & 4 deletions java/maven/src/org/netbeans/modules/maven/TestChecker.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,17 @@ public class TestChecker implements PrerequisitesChecker {
{ //NOI18N - profile-tests is not really nice but well.
String test = config.getProperties().get("test");
String method = config.getProperties().get(DefaultReplaceTokenProvider.METHOD_NAME);
if (test != null && method != null) {
String enclosingType = config.getProperties().get(DefaultReplaceTokenProvider.ENCLOSING_TYPE_NAME);
if (test != null) {
config.setProperty(DefaultReplaceTokenProvider.METHOD_NAME, null);
config.setProperty("test", test + '#' + method);
config.setProperty(DefaultReplaceTokenProvider.ENCLOSING_TYPE_NAME, null);
// ensure that maven executes all the methods in embedded classes too.
String methodConstraint = method == null ? "," + test + "$*" : "#" + method;
if (enclosingType != null) {
config.setProperty("test", test + "$" + enclosingType + methodConstraint);
} else {
config.setProperty("test", test + methodConstraint);
}
}
}
if (ActionProviderImpl.COMMAND_INTEGRATION_TEST_SINGLE.equals(action) ||
Expand All @@ -65,9 +73,16 @@ public class TestChecker implements PrerequisitesChecker {
{
String test = config.getProperties().get("it.test"); //NOI18N
String method = config.getProperties().get(DefaultReplaceTokenProvider.METHOD_NAME);
if (test != null && method != null) {
String enclosingType = config.getProperties().get(DefaultReplaceTokenProvider.ENCLOSING_TYPE_NAME);
if (test != null) {
config.setProperty(DefaultReplaceTokenProvider.METHOD_NAME, null);
config.setProperty("it.test", test + '#' + method); //NOI18N
config.setProperty(DefaultReplaceTokenProvider.ENCLOSING_TYPE_NAME, null);
String methodConstraint = method == null ? "," + test + "$*" : "#" + method;
if (enclosingType != null) {
config.setProperty("it.test", test + "$" + enclosingType + methodConstraint);
} else {
config.setProperty("it.test", test + methodConstraint);
}
}
}
if (MavenSettings.getDefault().isSkipTests()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public class DefaultReplaceTokenProvider implements ReplaceTokenProvider, Action
static final String PROJECTS = "projects";//NOI18N
static final String ABSOLUTE_PATH = "absolutePathName";
public static final String METHOD_NAME = "nb.single.run.methodName"; //NOI18N
public static final String ENCLOSING_TYPE_NAME = "nb.single.run.enclosingType"; //NOI18N
private static final String VARIABLE_PREFIX = "var."; //NOI18N
// as defined in org.netbeans.modules.project.ant.VariablesModel
public static String[] fileBasedProperties = new String[] {
Expand Down Expand Up @@ -246,6 +247,9 @@ private static FileObject[] extractFileObjectsfromLookup(Lookup lookup) {
//sort of hack to push the method name through the current apis..
SingleMethod method = methods.iterator().next();
replaceMap.put(METHOD_NAME, method.getMethodName());
if(method.getNestedClass() != null) {
replaceMap.put(ENCLOSING_TYPE_NAME, method.getNestedClass().getClassName());
}
}

if (group != null &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ private RunConfig mapGoalsToAction(Project project, String actionName, Map<Strin
if (replaceMap.containsKey(DefaultReplaceTokenProvider.METHOD_NAME)) {
//sort of hack to push the method name through the current apis..
mrc.setProperty(DefaultReplaceTokenProvider.METHOD_NAME, replaceMap.get(DefaultReplaceTokenProvider.METHOD_NAME));
mrc.setProperty(DefaultReplaceTokenProvider.ENCLOSING_TYPE_NAME, replaceMap.get(DefaultReplaceTokenProvider.ENCLOSING_TYPE_NAME));
}
return mrc;
}
Expand Down