Skip to content

Commit 9bcdbe5

Browse files
Merge pull request #219 from refactorfirst/coderabbit/add-pr-218-tests/696753a2
Add tests for Java 25 parser fallback and CycleRanker graph generation
2 parents 15c6bc9 + 4d55894 commit 9bcdbe5

2 files changed

Lines changed: 78 additions & 1 deletion

File tree

‎codebase-graph-builder/src/test/java/org/hjug/graphbuilder/graphbuilder/Java25ParserFactoryTest.java‎

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,22 @@ void versionedVariantCreatesWorkingJava25Parser() throws Exception {
103103
+ parsed.get(0).getClass().getName());
104104
}
105105

106+
@DisplayName("T2: versioned variant falls back when the Java 25 parser is unavailable")
107+
@EnabledForJreRange(min = JRE.JAVA_25)
108+
@Test
109+
void versionedVariantFallsBackWhenJava25ParserIsUnavailable() throws Exception {
110+
Class<?> versionedFactory = loadVersionedFactoryWithoutJava25Parser();
111+
112+
Object result = assertDoesNotThrow(
113+
() -> versionedFactory.getMethod("createJava25Parser").invoke(null),
114+
"The versioned factory must contain parser linkage failures");
115+
116+
assertInstanceOf(Optional.class, result);
117+
assertTrue(
118+
((Optional<?>) result).isEmpty(),
119+
"A missing Java25Parser must return an empty Optional so the caller can use its standard fallback");
120+
}
121+
106122
@DisplayName("T3: versioned and base variants expose identical public API (JEP 238 parity)")
107123
@EnabledForJreRange(min = JRE.JAVA_25)
108124
@Test
@@ -122,6 +138,14 @@ void versionedVariantExposesIdenticalPublicApi() throws Exception {
122138
* inactive).
123139
*/
124140
private static Class<?> loadVersionedFactory() throws Exception {
141+
return loadVersionedFactory(false);
142+
}
143+
144+
private static Class<?> loadVersionedFactoryWithoutJava25Parser() throws Exception {
145+
return loadVersionedFactory(true);
146+
}
147+
148+
private static Class<?> loadVersionedFactory(boolean hideJava25Parser) throws Exception {
125149
assumeTrue(
126150
Files.exists(VERSIONED_CLASSES_DIR.resolve(VERSIONED_CLASS_RELATIVE_PATH)),
127151
"Versioned factory class only exists when built on JDK 25+");
@@ -138,7 +162,15 @@ protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundE
138162
}
139163
};
140164
URLClassLoader loader =
141-
new URLClassLoader(new URL[] {VERSIONED_CLASSES_DIR.toUri().toURL()}, filteredParent);
165+
new URLClassLoader(new URL[] {VERSIONED_CLASSES_DIR.toUri().toURL()}, filteredParent) {
166+
@Override
167+
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
168+
if (hideJava25Parser && name.equals("org.openrewrite.java.Java25Parser")) {
169+
throw new ClassNotFoundException(name);
170+
}
171+
return super.loadClass(name, resolve);
172+
}
173+
};
142174
return Class.forName(FACTORY_FQN, false, loader);
143175
}
144176

‎cost-benefit-calculator/src/test/java/org/hjug/cbc/CycleRankerGraphGenerationTest.java‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
import org.junit.jupiter.api.DisplayName;
1010
import org.junit.jupiter.api.Test;
1111
import org.junit.jupiter.api.io.TempDir;
12+
import org.junit.jupiter.params.ParameterizedTest;
13+
import org.junit.jupiter.params.provider.CsvSource;
14+
import org.junit.jupiter.params.provider.NullAndEmptySource;
1215

1316
/**
1417
* Verifies {@link CycleRanker#generateClassReferencesGraph(boolean, String)}
@@ -41,4 +44,46 @@ public void hello() {}
4144
assertNotNull(dto);
4245
assertTrue(dto.getClassReferencesGraph().containsVertex("com.example.Plain"));
4346
}
47+
48+
@ParameterizedTest
49+
@NullAndEmptySource
50+
@DisplayName("generateClassReferencesGraph rejects a missing source directory")
51+
void rejectsMissingSourceDirectory(String repositoryPath) {
52+
CycleRanker ranker = new CycleRanker(repositoryPath, tempDir.toString());
53+
54+
IllegalArgumentException exception = assertThrows(
55+
IllegalArgumentException.class, () -> ranker.generateClassReferencesGraph(false, "src/test"));
56+
57+
assertEquals("Source directory cannot be null or empty", exception.getMessage());
58+
assertNull(ranker.getCodebaseGraphDTO(), "A rejected request must not populate the graph DTO");
59+
}
60+
61+
@ParameterizedTest(name = "excludeTests={0} should include custom test source={1}")
62+
@CsvSource({"true, false", "false, true"})
63+
@DisplayName("generateClassReferencesGraph forwards test exclusion configuration")
64+
void forwardsTestExclusionConfiguration(boolean excludeTests, boolean expectTestSource) throws IOException {
65+
writeJava(tempDir.resolve("src/main/java/com/example/ProductionClass.java"), "com.example", "ProductionClass");
66+
writeJava(tempDir.resolve("custom-tests/com/example/FixtureClass.java"), "com.example", "FixtureClass");
67+
68+
CycleRanker ranker = new CycleRanker(tempDir.toString(), tempDir.toString());
69+
CodebaseGraphDTO dto = ranker.generateClassReferencesGraph(excludeTests, "custom-tests");
70+
71+
assertTrue(dto.getClassReferencesGraph().containsVertex("com.example.ProductionClass"));
72+
assertEquals(
73+
expectTestSource,
74+
dto.getClassReferencesGraph().containsVertex("com.example.FixtureClass"),
75+
"The custom test source directory must follow the caller's exclusion setting");
76+
assertSame(dto, ranker.getCodebaseGraphDTO(), "The generated DTO must remain available to cycle ranking");
77+
}
78+
79+
private static void writeJava(Path path, String packageName, String className) throws IOException {
80+
Files.createDirectories(path.getParent());
81+
Files.writeString(
82+
path,
83+
"""
84+
package %s;
85+
public class %s {}
86+
"""
87+
.formatted(packageName, className));
88+
}
4489
}

0 commit comments

Comments
 (0)