jdaugherty commented on code in PR #432:
URL: 
https://github.com/apache/grails-intellij-plugin/pull/432#discussion_r4191542891


##########
plugin/src/main/java/org/apache/grails/intellij/plugin/projectView/impl/Grails3NodeProvider.java:
##########
@@ -77,4 +118,52 @@ public class Grails3NodeProvider implements 
GrailsViewNodeProvider {
     result.add(new GrailsPluginsNode(application.getProject(), settings));
     return result;
   }
+
+  /**
+   * Discovers the test source roots to lift out of {@code src}. {@code 
ProjectFileIndex} is consulted
+   * first, but only as positive evidence: a module registers the whole 
content root as one SOURCE root,
+   * so it reports a non-test type for every candidate — including in this 
project's own light fixture —
+   * and on its own would lift nothing. The structural rule below is therefore 
the heuristic that
+   * carries discovery wherever the module does not register each phase as its 
own test source root.
+   */
+  private static @NotNull List<PsiDirectory> 
findTestSourceDirectories(@NotNull PsiDirectory src) {
+    ProjectFileIndex index = ProjectFileIndex.getInstance(src.getProject());
+    List<PsiDirectory> result = new ArrayList<>();
+    for (VirtualFile child : src.getVirtualFile().getChildren()) {
+      if (!child.isDirectory() || !isTestSourceRoot(index, child)) continue;
+      PsiDirectory directory = 
PsiManager.getInstance(src.getProject()).findDirectory(child);
+      if (directory != null) result.add(directory);
+    }
+    return result;
+  }
+
+  private static boolean isTestSourceRoot(@NotNull ProjectFileIndex index, 
@NotNull VirtualFile child) {
+    JpsModuleSourceRootType<?> type = index.getContainingSourceRootType(child);
+    if (type != null && type.isForTests()) return true;
+    // src/main is the production root, and a built-in phase is a test root 
whatever it holds. Any other
+    // child qualifies only on the shape of a Grails source root: it holds a 
conventional code source
+    // directory, which is what a custom testPhases entry generates.
+    //
+    // This rule assumes every non-main code-source root under src is a phase. 
A project with a
+    // non-standard production root there (src/legacy/groovy, say) has it 
lifted out of src and labelled
+    // Tests:legacy. Skipping the rule when the index reports a production 
root would not help: Gradle
+    // registers the whole content root as one SOURCE root, so the index 
reports non-test for every
+    // candidate and the rule would stop lifting anything at all.
+    String name = child.getName();
+    if ("main".equals(name)) return false;
+    if (PHASE_TITLES.containsKey(name)) return true;
+    for (VirtualFile grandChild : child.getChildren()) {
+      if (grandChild.isDirectory() && 
CODE_SOURCE_DIRS.contains(grandChild.getName())) return true;

Review Comment:
   [P2] Discover custom phases from the registered source roots
   
   The shape-based fallback moves production code into the test section even 
when the IDE knows it is production. I reproduced this by adding 
`src/generated/java/GeneratedClient.java` and registering `src/generated/java` 
as `JavaSourceRootType.SOURCE`: `createNodes()` still emits `Tests:generated`, 
and the `src` filter excludes that directory.
   
   The index lookup above checks `src/generated`, not the registered root below 
it. This also causes the opposite failure: registering 
`src/smoke-test/resources` as `JavaResourceRootType.TEST_RESOURCE` does not 
produce a phase node when there is no Groovy/Java directory. Both cases fail in 
light-fixture tests configured through `ModuleRootModificationUtil.updateModel` 
and `ContentEntry.addSourceFolder`.
   
   Please derive custom phases from actual registered test source/resource 
roots and map them to their direct child of `src`, rather than treating every 
non-main code directory as a test. A conventional-name fallback can still cover 
the built-in phases before import. The fixture can register roots explicitly 
for this coverage. Also, `ProjectFileIndex.isInTestSourceContent()` is 
available on this platform (inherited from `FileIndex`); the reproducer 
compiles and uses it successfully, as does the existing 
`GspFileImpl.getFileResolveScope()`.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to