Skip to content

Commit 6a8c8cc

Browse files
committed
upload a reproducer
1 parent f50d642 commit 6a8c8cc

File tree

1 file changed

+134
-0
lines changed

1 file changed

+134
-0
lines changed

reproduce_issue.groovy

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import groovy.transform.Field
2+
3+
@Field
4+
String javaSource = """
5+
package io.micronaut.reproduce;
6+
7+
import io.micronaut.context.ApplicationContext;
8+
import io.micronaut.context.annotation.Bean;
9+
import jakarta.inject.Inject;
10+
11+
@Bean
12+
public class Parent {
13+
@Inject ApplicationContext context;
14+
15+
public ApplicationContext getContext() {
16+
return context;
17+
}
18+
}
19+
"""
20+
21+
@Field
22+
String kotlinSource = """
23+
package io.micronaut.reproduce
24+
25+
import io.micronaut.context.annotation.Bean
26+
import io.micronaut.runtime.Micronaut
27+
import jakarta.annotation.PostConstruct
28+
import io.micronaut.context.ApplicationContext // Import ApplicationContext
29+
30+
@Bean
31+
open class Child : Parent() { // Use 'open' for inheritance
32+
lateinit var injectedContext: ApplicationContext // A separate field to hold context from Parent if needed for verification in this class
33+
34+
@PostConstruct
35+
fun init() {
36+
// Here, we check if the context from the Java parent is injected
37+
// The issue states 'check(context != null)' from the original report
38+
// So we will try to access the context from the parent and ensure it's not null.
39+
if (context == null) {
40+
println("ERROR: context from Java Parent is NULL! Issue reproduced.")
41+
throw IllegalStateException("Context from Java Parent was not injected.")
42+
}
43+
this.injectedContext = context
44+
}
45+
}
46+
"""
47+
48+
@Field
49+
String testSource = """
50+
package io.micronaut.reproduce
51+
52+
import io.micronaut.context.ApplicationContext
53+
import io.micronaut.runtime.Micronaut
54+
import spock.lang.Specification
55+
import spock.lang.AutoCleanup
56+
57+
class ReproduceIssueSpec extends Specification {
58+
59+
@AutoCleanup
60+
ApplicationContext applicationContext
61+
62+
void "test Kotlin child inherits injected field from Java parent with KSP"() {
63+
given:
64+
applicationContext = Micronaut.run()
65+
66+
when:
67+
Child child = applicationContext.getBean(Child)
68+
69+
then:
70+
// The @PostConstruct in Child should have thrown an exception if context is null
71+
// If it reaches here, it means @PostConstruct passed, but we'll re-check to be safe.
72+
child.context != null
73+
74+
// This assertion directly reflects the check in the Kotlin class's @PostConstruct
75+
// If the @PostConstruct didn't throw, this should pass.
76+
// If the bug is reproduced, the @PostConstruct *should* throw, causing the test to fail.
77+
// So a test failure means the bug is reproduced.
78+
}
79+
}
80+
"""
81+
82+
// THIS IS WHERE THE YOUR TEST SOURCE WILL BE PLACED
83+
def testSuiteDir = new File("test-suite/src/test/groovy/io/micronaut/reproduce")
84+
def testSuiteKotlinJavaTestDir = new File("test-suite-kotlin/src/test/java/io/micronaut/reproduce")
85+
def testSuiteKotlinKotlinTestDir = new File("test-suite-kotlin/src/test/kotlin/io/micronaut/reproduce")
86+
87+
try {
88+
// Create directories
89+
testSuiteDir.mkdirs()
90+
testSuiteKotlinJavaTestDir.mkdirs()
91+
testSuiteKotlinKotlinTestDir.mkdirs()
92+
93+
// Write source files
94+
new File(testSuiteKotlinJavaTestDir, "Parent.java").write(javaSource)
95+
new File(testSuiteKotlinKotlinTestDir, "Child.kt").write(kotlinSource)
96+
def testFile = new File(testSuiteDir, "ReproduceIssueSpec.groovy")
97+
testFile.write(testSource)
98+
99+
// Command to invoke the test script
100+
// We need to build and test test-suite-kotlin first to ensure KSP processing
101+
// Then run the test-suite test which depends on it
102+
def command = "./gradlew :test-suite-kotlin:test :test-suite:test --tests io.micronaut.reproduce.ReproduceIssueSpec"
103+
println "Executing command: $command"
104+
def process = command.execute()
105+
process.waitForProcessOutput(System.out, System.err)
106+
def gradleExitCode = process.exitValue()
107+
108+
// Analyze Gradle exit code
109+
if (gradleExitCode == 0) {
110+
// If Gradle exited with 0, the test passed. This means the bug was NOT reproduced.
111+
println "Test passed, issue NOT reproduced."
112+
System.exit(0)
113+
} else {
114+
// If Gradle exited with non-zero, the test failed. This indicates the bug was reproduced.
115+
// The Child's @PostConstruct should throw an exception if 'context' is null,
116+
// which would cause the test to fail.
117+
println "Test failed (Gradle exit code: $gradleExitCode), issue REPRODUCED."
118+
System.exit(129)
119+
}
120+
} catch (Exception e) {
121+
e.printStackTrace()
122+
System.exit(1) // Script error
123+
} finally {
124+
// Clean up created files and directories
125+
println "Cleaning up temporary files..."
126+
new File(testSuiteKotlinJavaTestDir, "Parent.java").delete()
127+
new File(testSuiteKotlinKotlinTestDir, "Child.kt").delete()
128+
new File(testSuiteDir, "ReproduceIssueSpec.groovy").delete()
129+
130+
// Attempt to delete parent directories, they might not be empty
131+
testSuiteDir.deleteDir()
132+
testSuiteKotlinJavaTestDir.deleteDir()
133+
testSuiteKotlinKotlinTestDir.deleteDir()
134+
}

0 commit comments

Comments
 (0)