diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9f0bb50d0..3e5c4be05 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] # Project versions -nativeBuildTools = "0.9.28" +nativeBuildTools = "0.10.5" # External dependencies junitPlatform = "1.9.2" diff --git a/metadata/index.json b/metadata/index.json index 05ddffc6b..7e750e4ae 100644 --- a/metadata/index.json +++ b/metadata/index.json @@ -341,6 +341,10 @@ "allowed-packages" : [ "org.jooq" ], "directory" : "org.jooq/jooq", "module" : "org.jooq:jooq" +}, { + "allowed-packages" : [ "org.junit.jupiter", "org.junit" ], + "directory" : "org.junit.jupiter/junit-jupiter", + "module" : "org.junit.jupiter:junit-jupiter" }, { "allowed-packages" : [ "org.liquibase", "liquibase" ], "directory" : "org.liquibase/liquibase-core", diff --git a/metadata/org.junit.jupiter/junit-jupiter/5.11.0/index.json b/metadata/org.junit.jupiter/junit-jupiter/5.11.0/index.json new file mode 100644 index 000000000..3bf120937 --- /dev/null +++ b/metadata/org.junit.jupiter/junit-jupiter/5.11.0/index.json @@ -0,0 +1,4 @@ +[ + "resource-config.json", + "reflect-config.json" +] \ No newline at end of file diff --git a/metadata/org.junit.jupiter/junit-jupiter/5.11.0/reflect-config.json b/metadata/org.junit.jupiter/junit-jupiter/5.11.0/reflect-config.json new file mode 100644 index 000000000..d28ef71ab --- /dev/null +++ b/metadata/org.junit.jupiter/junit-jupiter/5.11.0/reflect-config.json @@ -0,0 +1,391 @@ +[ +{ + "condition":{"typeReachable":"org.junit.internal.builders.SuiteMethodBuilder"}, + "name":"basic.BasicTest", + "methods":[{"name":"suite","parameterTypes":[] }] +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.descriptor.ExtensionUtils"}, + "name":"basic.BasicTest", + "allDeclaredFields":true, + "queryAllDeclaredConstructors":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.descriptor.LifecycleMethodUtils"}, + "name":"basic.BasicTest", + "queryAllDeclaredMethods":true, + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.discovery.ClassSelectorResolver"}, + "name":"basic.BasicTest", + "queryAllDeclaredMethods":true, + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.discovery.predicates.IsTestClassWithTests"}, + "name":"basic.BasicTest", + "queryAllDeclaredMethods":true, + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.extension.AutoCloseExtension"}, + "name":"basic.BasicTest", + "allDeclaredFields":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.extension.TempDirectory"}, + "name":"basic.BasicTest", + "allDeclaredFields":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.extension.TimeoutExtension"}, + "name":"basic.BasicTest", + "methods":[{"name":"resourceTest","parameterTypes":[] }] +}, +{ + "condition":{"typeReachable":"org.junit.platform.commons.util.AnnotationUtils"}, + "name":"basic.BasicTest" +}, +{ + "condition":{"typeReachable":"org.junit.platform.commons.util.ReflectionUtils"}, + "name":"basic.BasicTest", + "allDeclaredClasses":true +}, +{ + "condition":{"typeReachable":"org.junit.vintage.engine.discovery.DefensiveAllDefaultPossibilitiesBuilder$DefensiveJUnit4Builder"}, + "name":"basic.BasicTest", + "queryAllDeclaredMethods":true, + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.internal.MethodSorter"}, + "name":"java.lang.Object", + "queryAllDeclaredMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.runners.model.TestClass"}, + "name":"java.lang.Object", + "allDeclaredFields":true +}, +{ + "condition":{"typeReachable":"org.junit.platform.launcher.listeners.OutputDir"}, + "name":"java.security.SecureRandomParameters" +}, +{ + "condition":{"typeReachable":"org.junit.runners.model.FrameworkMethod$1"}, + "name":"org.hamcrest.core.Every", + "queryAllDeclaredMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.platform.launcher.listeners.OutputDir"}, + "name":"sun.security.provider.NativePRNG", + "methods":[{"name":"","parameterTypes":[] }, {"name":"","parameterTypes":["java.security.SecureRandomParameters"] }] +}, +{ + "condition":{"typeReachable":"org.junit.platform.launcher.listeners.OutputDir"}, + "name":"sun.security.provider.SHA", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "condition":{"typeReachable":"org.junit.internal.builders.SuiteMethodBuilder"}, + "name":"tests.ComplexTest", + "methods":[{"name":"suite","parameterTypes":[] }] +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.descriptor.ExtensionUtils"}, + "name":"tests.ComplexTest", + "allDeclaredFields":true, + "queryAllDeclaredConstructors":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.descriptor.LifecycleMethodUtils"}, + "name":"tests.ComplexTest", + "queryAllDeclaredMethods":true, + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.discovery.ClassSelectorResolver"}, + "name":"tests.ComplexTest", + "queryAllDeclaredMethods":true, + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.discovery.predicates.IsTestClassWithTests"}, + "name":"tests.ComplexTest", + "queryAllDeclaredMethods":true, + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.extension.AutoCloseExtension"}, + "name":"tests.ComplexTest", + "allDeclaredFields":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.extension.TempDirectory"}, + "name":"tests.ComplexTest", + "allDeclaredFields":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.extension.TimeoutExtension"}, + "name":"tests.ComplexTest", + "methods":[{"name":"accessFiledReflectively","parameterTypes":[] }, {"name":"accessMethodReflectively","parameterTypes":[] }, {"name":"callMethodFromOtherClass","parameterTypes":[] }, {"name":"resourceTest","parameterTypes":[] }] +}, +{ + "condition":{"typeReachable":"org.junit.platform.commons.util.AnnotationUtils"}, + "name":"tests.ComplexTest" +}, +{ + "condition":{"typeReachable":"org.junit.platform.commons.util.ReflectionUtils"}, + "name":"tests.ComplexTest", + "allDeclaredClasses":true +}, +{ + "condition":{"typeReachable":"org.junit.vintage.engine.discovery.DefensiveAllDefaultPossibilitiesBuilder$DefensiveJUnit4Builder"}, + "name":"tests.ComplexTest", + "queryAllDeclaredMethods":true, + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.internal.builders.SuiteMethodBuilder"}, + "name":"tests.JUnitAnnotationsTests", + "methods":[{"name":"suite","parameterTypes":[] }] +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor"}, + "name":"tests.JUnitAnnotationsTests" +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor$$Lambda$471/0x000078c708184000"}, + "name":"tests.JUnitAnnotationsTests" +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.descriptor.ClassTestDescriptor"}, + "name":"tests.JUnitAnnotationsTests" +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.descriptor.ExtensionUtils"}, + "name":"tests.JUnitAnnotationsTests", + "queryAllDeclaredConstructors":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.descriptor.LifecycleMethodUtils"}, + "name":"tests.JUnitAnnotationsTests", + "queryAllDeclaredMethods":true, + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.discovery.ClassSelectorResolver"}, + "name":"tests.JUnitAnnotationsTests", + "queryAllDeclaredMethods":true, + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.discovery.predicates.IsTestClassWithTests"}, + "name":"tests.JUnitAnnotationsTests", + "queryAllDeclaredMethods":true, + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.execution.ConstructorInvocation"}, + "name":"tests.JUnitAnnotationsTests", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.execution.MethodInvocation"}, + "name":"tests.JUnitAnnotationsTests" +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.extension.TimeoutExtension"}, + "name":"tests.JUnitAnnotationsTests", + "methods":[{"name":"beforeAndAfterEachTest1","parameterTypes":[] }, {"name":"beforeAndAfterEachTest2","parameterTypes":[] }, {"name":"beforeAndAfterEachTest3","parameterTypes":[] }, {"name":"checkIfThisComesLast","parameterTypes":[] }, {"name":"initializeNumberOfRepetitions","parameterTypes":[] }, {"name":"repeatedTest","parameterTypes":["org.junit.jupiter.api.RepetitionInfo"] }, {"name":"setAfterEach","parameterTypes":[] }, {"name":"setBeforeEach","parameterTypes":[] }, {"name":"singleFieldSource","parameterTypes":["java.lang.String"] }, {"name":"test","parameterTypes":["java.lang.String"] }, {"name":"testWithExternalFieldSource","parameterTypes":["java.lang.String"] }] +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.params.provider.MethodArgumentsProvider"}, + "name":"tests.JUnitAnnotationsTests" +}, +{ + "condition":{"typeReachable":"org.junit.platform.commons.util.AnnotationUtils"}, + "name":"tests.JUnitAnnotationsTests" +}, +{ + "condition":{"typeReachable":"org.junit.platform.commons.util.ReflectionUtils"}, + "name":"tests.JUnitAnnotationsTests", + "allDeclaredFields":true, + "allDeclaredClasses":true, + "queryAllDeclaredMethods":true, + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.vintage.engine.discovery.DefensiveAllDefaultPossibilitiesBuilder$DefensiveJUnit4Builder"}, + "name":"tests.JUnitAnnotationsTests", + "queryAllDeclaredMethods":true, + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.internal.builders.SuiteMethodBuilder"}, + "name":"tests.OrderTests", + "methods":[{"name":"suite","parameterTypes":[] }] +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.descriptor.ExtensionUtils"}, + "name":"tests.OrderTests", + "allDeclaredFields":true, + "queryAllDeclaredConstructors":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.descriptor.LifecycleMethodUtils"}, + "name":"tests.OrderTests", + "queryAllDeclaredMethods":true, + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.discovery.ClassSelectorResolver"}, + "name":"tests.OrderTests", + "queryAllDeclaredMethods":true, + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.discovery.predicates.IsTestClassWithTests"}, + "name":"tests.OrderTests", + "queryAllDeclaredMethods":true, + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.extension.AutoCloseExtension"}, + "name":"tests.OrderTests", + "allDeclaredFields":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.extension.TempDirectory"}, + "name":"tests.OrderTests", + "allDeclaredFields":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.extension.TimeoutExtension"}, + "name":"tests.OrderTests", + "methods":[{"name":"firstTest","parameterTypes":[] }, {"name":"secondTest","parameterTypes":[] }, {"name":"thirdTest","parameterTypes":[] }] +}, +{ + "condition":{"typeReachable":"org.junit.platform.commons.util.AnnotationUtils"}, + "name":"tests.OrderTests" +}, +{ + "condition":{"typeReachable":"org.junit.platform.commons.util.ReflectionUtils"}, + "name":"tests.OrderTests", + "allDeclaredClasses":true +}, +{ + "condition":{"typeReachable":"org.junit.vintage.engine.discovery.DefensiveAllDefaultPossibilitiesBuilder$DefensiveJUnit4Builder"}, + "name":"tests.OrderTests", + "queryAllDeclaredMethods":true, + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.internal.MethodSorter"}, + "name":"tests.VintageTests", + "queryAllDeclaredMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.internal.builders.SuiteMethodBuilder"}, + "name":"tests.VintageTests", + "methods":[{"name":"suite","parameterTypes":[] }] +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.discovery.ClassSelectorResolver"}, + "name":"tests.VintageTests", + "queryAllDeclaredMethods":true, + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.discovery.predicates.IsTestClassWithTests"}, + "name":"tests.VintageTests", + "allDeclaredClasses":true +}, +{ + "condition":{"typeReachable":"org.junit.runners.BlockJUnit4ClassRunner"}, + "name":"tests.VintageTests", + "queryAllPublicConstructors":true, + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "condition":{"typeReachable":"org.junit.runners.model.FrameworkMethod$1"}, + "name":"tests.VintageTests", + "methods":[{"name":"testEvery","parameterTypes":[] }, {"name":"testExpectedException","parameterTypes":[] }, {"name":"testExpectedExceptionCause","parameterTypes":[] }] +}, +{ + "condition":{"typeReachable":"org.junit.runners.model.TestClass"}, + "name":"tests.VintageTests", + "allDeclaredFields":true, + "queryAllPublicConstructors":true +}, +{ + "condition":{"typeReachable":"org.junit.vintage.engine.descriptor.TestSourceProvider"}, + "name":"tests.VintageTests", + "queryAllDeclaredMethods":true, + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.vintage.engine.discovery.DefensiveAllDefaultPossibilitiesBuilder$DefensiveJUnit4Builder"}, + "name":"tests.VintageTests", + "queryAllDeclaredMethods":true, + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.internal.builders.SuiteMethodBuilder"}, + "name":"tests.common.Fruits", + "methods":[{"name":"suite","parameterTypes":[] }] +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.discovery.ClassSelectorResolver"}, + "name":"tests.common.Fruits", + "queryAllDeclaredMethods":true, + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.discovery.predicates.IsTestClassWithTests"}, + "name":"tests.common.Fruits", + "allDeclaredClasses":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.extension.TimeoutExtension"}, + "name":"tests.common.Fruits", + "fields":[{"name":"fruits"}], + "methods":[{"name":"getBlackberry","parameterTypes":[] }] +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.params.provider.FieldArgumentsProvider"}, + "name":"tests.common.Fruits", + "allDeclaredFields":true +}, +{ + "condition":{"typeReachable":"org.junit.vintage.engine.discovery.DefensiveAllDefaultPossibilitiesBuilder$DefensiveJUnit4Builder"}, + "name":"tests.common.Fruits", + "queryAllDeclaredMethods":true, + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.descriptor.LifecycleMethodUtils"}, + "name":"tests.common.TestInterface", + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.discovery.ClassSelectorResolver"}, + "name":"tests.common.TestInterface", + "queryAllPublicMethods":true +}, +{ + "condition":{"typeReachable":"org.junit.jupiter.engine.execution.DefaultExecutableInvoker"}, + "name":"tests.common.TestInterface", + "methods":[{"name":"names","parameterTypes":[] }] +}, +{ + "condition":{"typeReachable":"org.junit.platform.commons.util.AnnotationUtils"}, + "name":"tests.common.TestInterface" +}, +{ + "condition":{"typeReachable":"org.junit.platform.commons.util.ReflectionUtils"}, + "name":"tests.common.TestInterface", + "allPublicFields":true +} +] \ No newline at end of file diff --git a/metadata/org.junit.jupiter/junit-jupiter/5.11.0/resource-config.json b/metadata/org.junit.jupiter/junit-jupiter/5.11.0/resource-config.json new file mode 100644 index 000000000..a0c754a33 --- /dev/null +++ b/metadata/org.junit.jupiter/junit-jupiter/5.11.0/resource-config.json @@ -0,0 +1,14 @@ +{ + "resources":{ + "includes":[{ + "condition":{"typeReachable":"org.junit.platform.launcher.core.LauncherFactory"}, + "pattern":"\\QMETA-INF/services/org.junit.platform.engine.TestEngine\\E" + }, { + "condition":{"typeReachable":"org.junit.platform.launcher.core.LauncherFactory"}, + "pattern":"\\QMETA-INF/services/org.junit.platform.launcher.TestExecutionListener\\E" + }, { + "condition":{"typeReachable":"org.junit.jupiter.engine.extension.TimeoutExtension"}, + "pattern":"\\Qresource.txt\\E" + }]}, + "bundles":[] +} \ No newline at end of file diff --git a/metadata/org.junit.jupiter/junit-jupiter/index.json b/metadata/org.junit.jupiter/junit-jupiter/index.json new file mode 100644 index 000000000..c30dea0e4 --- /dev/null +++ b/metadata/org.junit.jupiter/junit-jupiter/index.json @@ -0,0 +1,10 @@ +[ + { + "latest": true, + "metadata-version": "5.11.0", + "module": "org.junit.jupiter:junit-jupiter", + "tested-versions": [ + "5.11.0" + ] + } +] diff --git a/tests/src/index.json b/tests/src/index.json index 54318b2bf..07d1340fa 100644 --- a/tests/src/index.json +++ b/tests/src/index.json @@ -179,28 +179,28 @@ "versions" : [ "2.16.11" ] } ] }, { - "test-project-path" : "io.netty/netty-common/4.1.80.Final", + "test-project-path" : "io.netty/netty-common/4.1.115.Final", "libraries" : [ { "name" : "io.netty:netty-common", - "versions" : [ "4.1.80.Final" ] + "versions" : [ "4.1.115.Final" ] } ] }, { - "test-project-path" : "io.netty/netty-transport/4.1.80.Final", + "test-project-path" : "io.netty/netty-common/4.1.80.Final", "libraries" : [ { - "name" : "io.netty:netty-transport", + "name" : "io.netty:netty-common", "versions" : [ "4.1.80.Final" ] } ] }, { - "test-project-path" : "io.netty/netty-common/4.1.115.Final", + "test-project-path" : "io.netty/netty-transport/4.1.115.Final", "libraries" : [ { - "name" : "io.netty:netty-common", + "name" : "io.netty:netty-transport", "versions" : [ "4.1.115.Final" ] } ] }, { - "test-project-path" : "io.netty/netty-transport/4.1.115.Final", + "test-project-path" : "io.netty/netty-transport/4.1.80.Final", "libraries" : [ { "name" : "io.netty:netty-transport", - "versions" : [ "4.1.115.Final" ] + "versions" : [ "4.1.80.Final" ] } ] }, { "test-project-path" : "io.opentelemetry/opentelemetry-exporter-jaeger/1.19.0", @@ -437,16 +437,16 @@ "versions" : [ "10.15.0" ] } ] }, { - "test-project-path": "org.flywaydb/flyway-core/10.20.0", - "libraries": [ { - "name": "org.flywaydb:flyway-core", - "versions": [ "10.20.0" ] + "test-project-path" : "org.flywaydb/flyway-core/10.20.0", + "libraries" : [ { + "name" : "org.flywaydb:flyway-core", + "versions" : [ "10.20.0" ] } ] }, { - "test-project-path": "org.flywaydb/flyway-core/10.20.1", - "libraries": [ { - "name": "org.flywaydb:flyway-core", - "versions": [ "10.20.1" ] + "test-project-path" : "org.flywaydb/flyway-core/10.20.1", + "libraries" : [ { + "name" : "org.flywaydb:flyway-core", + "versions" : [ "10.20.1" ] } ] }, { "test-project-path" : "org.flywaydb/flyway-core/9.0.1", @@ -586,6 +586,12 @@ "name" : "org.jooq:jooq", "versions" : [ "3.18.2" ] } ] +}, { + "test-project-path" : "org.junit.jupiter/junit-jupiter/5.11.0", + "libraries" : [ { + "name" : "org.junit.jupiter:junit-jupiter", + "versions" : [ "5.11.0" ] + } ] }, { "test-project-path" : "org.liquibase/liquibase-core/4.17.0", "libraries" : [ { @@ -682,4 +688,4 @@ "name" : "samples:docker", "versions" : [ "image-pull" ] } ] -} ] +} ] \ No newline at end of file diff --git a/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/.gitignore b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/.gitignore new file mode 100644 index 000000000..c98c7875b --- /dev/null +++ b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/.gitignore @@ -0,0 +1,4 @@ +gradlew.bat +gradlew +gradle/ +build/ diff --git a/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/build.gradle b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/build.gradle new file mode 100644 index 000000000..5bde37b3f --- /dev/null +++ b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/build.gradle @@ -0,0 +1,29 @@ +/* + * Copyright and related rights waived via CC0 + * + * You should have received a copy of the CC0 legalcode along with this + * work. If not, see . + */ + +plugins { + id "org.graalvm.internal.tck" +} + +String libraryVersion = tck.testedLibraryVersion.get() + +dependencies { + testImplementation "org.junit.vintage:junit-vintage-engine:5.11.0" + testImplementation "org.junit.jupiter:junit-jupiter:$libraryVersion" + testImplementation 'org.assertj:assertj-core:3.22.0' +} + +graalvmNative { + agent { + defaultMode = "conditional" + modes { + conditional { + userCodeFilterPath = "user-code-filter.json" + } + } + } +} diff --git a/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/gradle.properties b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/gradle.properties new file mode 100644 index 000000000..491996ac3 --- /dev/null +++ b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/gradle.properties @@ -0,0 +1,2 @@ +library.version = 5.11.0 +metadata.dir = org.junit.jupiter/junit-jupiter/5.11.0/ diff --git a/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/settings.gradle b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/settings.gradle new file mode 100644 index 000000000..53d56a15b --- /dev/null +++ b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/settings.gradle @@ -0,0 +1,13 @@ +pluginManagement { + def tckPath = Objects.requireNonNullElse( + System.getenv("GVM_TCK_TCKDIR"), + "../../../../tck-build-logic" + ) + includeBuild(tckPath) +} + +plugins { + id "org.graalvm.internal.tck-settings" version "1.0.0-SNAPSHOT" +} + +rootProject.name = 'org.junit.jupiter.junit-jupiter_tests' diff --git a/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/java/basic/BasicTest.java b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/java/basic/BasicTest.java new file mode 100644 index 000000000..35ee45d54 --- /dev/null +++ b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/java/basic/BasicTest.java @@ -0,0 +1,30 @@ +package basic; + +import org.junit.jupiter.api.Test; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class BasicTest { + + private static final String RESOURCE = "/resource.txt"; + + @Test + public void resourceTest() { + try(InputStream is = BasicTest.class.getResourceAsStream(RESOURCE)) { + assertNotNull(is); + InputStreamReader isr = new InputStreamReader(is); + BufferedReader br = new BufferedReader(isr); + + assertTrue(br.readLine().equalsIgnoreCase("Hello from resource!")); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/java/tests/ComplexTest.java b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/java/tests/ComplexTest.java new file mode 100644 index 000000000..7b6c7db78 --- /dev/null +++ b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/java/tests/ComplexTest.java @@ -0,0 +1,75 @@ +package tests; + +import org.junit.jupiter.api.Test; +import tests.common.Fruits; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.*; + + +public class ComplexTest { + + private static final String RESOURCE = "/resource.txt"; + + @Test + public void callMethodFromOtherClass() { + String fruit = Fruits.getSomeFruit(); + assertNotNull(fruit); + assertTrue(fruit.contains("berry")); + } + + @Test + public void accessMethodReflectively() { + try { + String methodName = "get" + "Blackberry"; + Method method = Fruits.class.getDeclaredMethod(methodName, (Class[]) null); + method.setAccessible(true); + + Fruits f = new Fruits(); + String retval = (String) method.invoke(f); + assertTrue(retval.equalsIgnoreCase("blackberry")); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + + @Test + public void accessFiledReflectively() { + try { + Field fruitsField = Fruits.class.getDeclaredField("fruits"); + fruitsField.setAccessible(true); + + Fruits f = new Fruits(); + List fruits = (List) fruitsField.get(f); + + assertEquals(3, fruits.size()); + assertEquals(3, fruits.stream().filter(fruit -> fruit.contains("berry")).collect(Collectors.toList()).size()); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + @Test + public void resourceTest() { + try(InputStream is = ComplexTest.class.getResourceAsStream(RESOURCE)) { + assertNotNull(is); + InputStreamReader isr = new InputStreamReader(is); + BufferedReader br = new BufferedReader(isr); + + assertTrue(br.readLine().equalsIgnoreCase("Hello from resource!")); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/java/tests/JUnitAnnotationsTests.java b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/java/tests/JUnitAnnotationsTests.java new file mode 100644 index 000000000..d1ee42731 --- /dev/null +++ b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/java/tests/JUnitAnnotationsTests.java @@ -0,0 +1,113 @@ +/* + * This Java source file was generated by the Gradle 'init' task. + */ +package tests; + +import org.junit.jupiter.api.*; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.FieldSource; +import tests.common.TestInterface; + + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + + +public class JUnitAnnotationsTests implements TestInterface { + + /* test Disabled tests */ + @Test + @Disabled + void skipThisTest() { + throw new RuntimeException("This test should not be executed!"); + } + + /* test MethodSource with Interface */ + @ParameterizedTest + @MethodSource("names") + void test(String name) { + assertEquals(5, name.length()); + assertTrue(name.startsWith("S")); + } + + /* test FieldSource with other class */ + @ParameterizedTest + @FieldSource("tests.common.Fruits#fruits") + void testWithExternalFieldSource(String fruit) { + assertTrue(fruit.contains("berry")); + } + + + /* test FieldSource with field from this class */ + static final List listOfFruits = Arrays.asList("apple", "ananas"); + + @ParameterizedTest + @FieldSource("listOfFruits") + void singleFieldSource(String fruit) { + assertTrue(fruit.startsWith("a")); + } + + + /* test RepeatedTest */ + private static int numberOfRepetitions = -1; + + @BeforeAll + static void initializeNumberOfRepetitions() { + /* if we don't execute this first, repeated tests will fail */ + numberOfRepetitions = 1; + } + + @AfterAll + static void checkIfThisComesLast() { + /* if this comes last, 3 repeated tests should have increased this value to 4 */ + assertEquals(4, numberOfRepetitions); + } + + @RepeatedTest(3) + void repeatedTest(RepetitionInfo repetitionInfo) { + assertEquals(repetitionInfo.getCurrentRepetition(), numberOfRepetitions); + numberOfRepetitions++; + } + + /* test BeforeEach and AfterEach annotations */ + private static int beforeEachTestValue = -1; + private static int afterEachTestValue = -1; + + @BeforeEach + void setBeforeEach() { + beforeEachTestValue = 0; + } + + @AfterEach + void setAfterEach() { + afterEachTestValue = -1; + } + + @Test + void beforeAndAfterEachTest1() { + assertEquals(0, beforeEachTestValue); + assertEquals(-1, afterEachTestValue); + beforeEachTestValue = (int) (Math.random() * 10 + 1); + afterEachTestValue = (int) (Math.random() * 10 + 1); + } + + @Test + void beforeAndAfterEachTest2() { + assertEquals(0, beforeEachTestValue); + assertEquals(-1, afterEachTestValue); + beforeEachTestValue = (int) (Math.random() * 10 + 1); + afterEachTestValue = (int) (Math.random() * 10 + 1); + } + + @Test + void beforeAndAfterEachTest3() { + assertEquals(0, beforeEachTestValue); + assertEquals(-1, afterEachTestValue); + beforeEachTestValue = (int) (Math.random() * 10 + 1); + afterEachTestValue = (int) (Math.random() * 10 + 1); + } + +} diff --git a/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/java/tests/OrderTests.java b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/java/tests/OrderTests.java new file mode 100644 index 000000000..d09936ced --- /dev/null +++ b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/java/tests/OrderTests.java @@ -0,0 +1,35 @@ +package tests; + +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; + +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class OrderTests { + /* tests execution order should be dictated by the @Order annotation */ + protected static String testOrderChecker = "First test"; + + @Test + @Order(2) + void secondTest() { + assertTrue(testOrderChecker.equalsIgnoreCase("Second test")); + testOrderChecker = null; + } + + @Test + @Order(3) + void thirdTest() { + assertNull(testOrderChecker); + } + + @Test + @Order(1) + void firstTest() { + assertTrue(testOrderChecker.equalsIgnoreCase("First test")); + testOrderChecker = "Second test"; + } +} diff --git a/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/java/tests/VintageTests.java b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/java/tests/VintageTests.java new file mode 100644 index 000000000..01c411401 --- /dev/null +++ b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/java/tests/VintageTests.java @@ -0,0 +1,45 @@ +package tests; + +import org.hamcrest.MatcherAssert; +import org.hamcrest.core.Every; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.util.Arrays; +import java.util.List; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; + +public class VintageTests { + + /* passes but with some exceptions ("as warning") */ + + @Test + public void testEvery() { + List numbers = Arrays.asList(1, 1, 1, 1); + MatcherAssert.assertThat(numbers, Every.everyItem(is(1))); + } + + @SuppressWarnings("deprecation") + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Test + public void testExpectedException() { + expectedException.expect(ArithmeticException.class); + throw new ArithmeticException(); + } + + @Test + public void testExpectedExceptionCause() { + expectedException.expectCause(instanceOf(ArithmeticException.class)); + try { + throw new ArithmeticException(); + } catch (ArithmeticException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/java/tests/common/Fruits.java b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/java/tests/common/Fruits.java new file mode 100644 index 000000000..c427250fc --- /dev/null +++ b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/java/tests/common/Fruits.java @@ -0,0 +1,19 @@ +package tests.common; + +import java.util.Arrays; +import java.util.List; + +public class Fruits { + + private static final List fruits = Arrays.asList("blackberry", "raspberry", "strawberry"); + + public static String getSomeFruit() { + int index = Math.random() > 0.5 ? 1 : 0; + return fruits.get(index); + } + + private String getBlackberry() { + return fruits.get(0); + } + +} diff --git a/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/java/tests/common/TestInterface.java b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/java/tests/common/TestInterface.java new file mode 100644 index 000000000..ab8e1bc2d --- /dev/null +++ b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/java/tests/common/TestInterface.java @@ -0,0 +1,10 @@ +package tests.common; + +import java.util.List; + +public interface TestInterface { + + static List names() { + return List.of("Sarah", "Susan"); + } +} diff --git a/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/java/tests/test-maker.sh b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/java/tests/test-maker.sh new file mode 100755 index 000000000..9a17096f8 --- /dev/null +++ b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/java/tests/test-maker.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +test_source="MassiveTests1.java" + +for i in {1..59} +do +# echo "$test_source" +# echo "$i" +# echo "./NewMassiveTest$i" + cp "$test_source" "./NewMassiveTest$i.java" + sed -i "/public class MassiveTests1 {/c\public class NewMassiveTest$i {" "./NewMassiveTest$i.java" +done diff --git a/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/resources/resource.txt b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/resources/resource.txt new file mode 100644 index 000000000..a07388701 --- /dev/null +++ b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/src/test/resources/resource.txt @@ -0,0 +1 @@ +Hello from resource! diff --git a/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/user-code-filter.json b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/user-code-filter.json new file mode 100644 index 000000000..0d8a015f4 --- /dev/null +++ b/tests/src/org.junit.jupiter/junit-jupiter/5.11.0/user-code-filter.json @@ -0,0 +1,6 @@ +{ + "rules": [ + {"excludeClasses": "**"}, + {"includeClasses": "org.junit.**"} + ] +} \ No newline at end of file diff --git a/tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck-harness.gradle b/tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck-harness.gradle index 62b27417c..9f7fdb7fd 100644 --- a/tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck-harness.gradle +++ b/tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck-harness.gradle @@ -10,14 +10,15 @@ plugins { } import groovy.json.JsonOutput +import org.graalvm.internal.tck.ContributionTask import org.graalvm.internal.tck.DockerTask import org.graalvm.internal.tck.ConfigFilesChecker import org.graalvm.internal.tck.ScaffoldTask import org.graalvm.internal.tck.GrypeTask import org.graalvm.internal.tck.TestedVersionUpdaterTask import org.graalvm.internal.tck.harness.tasks.CheckstyleInvocationTask -import org.graalvm.internal.tck.harness.tasks.FetchExistingLibrariesWithNewerVersionsTask -import org.graalvm.internal.tck.harness.tasks.GroupUnsupportedLibraries +import org.graalvm.internal.tck.updaters.FetchExistingLibrariesWithNewerVersionsTask +import org.graalvm.internal.tck.updaters.GroupUnsupportedLibraries import org.graalvm.internal.tck.harness.tasks.TestInvocationTask @@ -164,7 +165,7 @@ Provider generateMatrixDiffCoordinates = tasks.register("generateMatrixDif } } -// groovy tasks +// new library version updaters tasks tasks.register("fetchExistingLibrariesWithNewerVersions", FetchExistingLibrariesWithNewerVersionsTask.class) { task -> task.setGroup(METADATA_GROUP) task.setDescription("Returns list of all libraries coordinates") @@ -176,7 +177,13 @@ tasks.register("groupLibrariesByName", GroupUnsupportedLibraries.class) { task - task.setDescription("Extracts groups of libraries from github comments provided in a form of string.") } -// java tasks + +tasks.register("addTestedVersion", TestedVersionUpdaterTask.class) { task -> + task.setDescription("Updates list of tested versions.") + task.setGroup(METADATA_GROUP) +} + +// docker tasks tasks.register("checkAllowedDockerImages", GrypeTask.class) { task -> task.setDescription("Returns list of allowed docker images") task.setGroup(METADATA_GROUP) @@ -187,6 +194,8 @@ tasks.register("pullAllowedDockerImages", DockerTask.class) { task -> task.setGroup(METADATA_GROUP) } + +// contributing tasks tasks.register("scaffold", ScaffoldTask.class) { task -> task.setDescription("Creates a metadata and test scaffold for the given coordindates") task.setGroup(METADATA_GROUP) @@ -194,12 +203,12 @@ tasks.register("scaffold", ScaffoldTask.class) { task -> task.finalizedBy("spotlessApply") } -tasks.register("checkConfigFiles", ConfigFilesChecker.class) { task -> - task.setDescription("Checks content of config files for a new library.") +tasks.register("contribute", ContributionTask.class) { task -> + task.setDescription("Generates metadata and prepares pull request for contibuting on metadata repository based on provided tests.") task.setGroup(METADATA_GROUP) } -tasks.register("addTestedVersion", TestedVersionUpdaterTask.class) { task -> - task.setDescription("Updates list of tested versions.") +tasks.register("checkConfigFiles", ConfigFilesChecker.class) { task -> + task.setDescription("Checks content of config files for a new library.") task.setGroup(METADATA_GROUP) } diff --git a/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/TckExtension.java b/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/TckExtension.java index bf2c4fc38..eb31d97c4 100644 --- a/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/TckExtension.java +++ b/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/TckExtension.java @@ -18,11 +18,9 @@ import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; import org.gradle.process.ExecOperations; -import org.gradle.util.internal.VersionNumber; import javax.inject.Inject; import java.io.ByteArrayOutputStream; -import java.io.File; import java.io.IOException; import java.net.URI; import java.nio.charset.StandardCharsets; diff --git a/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/FetchExistingLibrariesWithNewerVersionsTask.groovy b/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/updaters/FetchExistingLibrariesWithNewerVersionsTask.groovy similarity index 99% rename from tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/FetchExistingLibrariesWithNewerVersionsTask.groovy rename to tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/updaters/FetchExistingLibrariesWithNewerVersionsTask.groovy index fed4c2776..6832ba0c5 100644 --- a/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/FetchExistingLibrariesWithNewerVersionsTask.groovy +++ b/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/updaters/FetchExistingLibrariesWithNewerVersionsTask.groovy @@ -1,4 +1,4 @@ -package org.graalvm.internal.tck.harness.tasks +package org.graalvm.internal.tck.updaters import com.fasterxml.jackson.annotation.JsonInclude diff --git a/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/GroupUnsupportedLibraries.groovy b/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/updaters/GroupUnsupportedLibraries.groovy similarity index 97% rename from tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/GroupUnsupportedLibraries.groovy rename to tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/updaters/GroupUnsupportedLibraries.groovy index 2ce8217a5..edf3874f7 100644 --- a/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/harness/tasks/GroupUnsupportedLibraries.groovy +++ b/tests/tck-build-logic/src/main/groovy/org/graalvm/internal/tck/updaters/GroupUnsupportedLibraries.groovy @@ -1,4 +1,4 @@ -package org.graalvm.internal.tck.harness.tasks +package org.graalvm.internal.tck.updaters import org.gradle.api.DefaultTask import org.gradle.api.provider.Property diff --git a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/ContributionTask.java b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/ContributionTask.java new file mode 100644 index 000000000..076138f39 --- /dev/null +++ b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/ContributionTask.java @@ -0,0 +1,583 @@ +package org.graalvm.internal.tck; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import org.graalvm.internal.tck.model.MetadataIndexEntry; +import org.graalvm.internal.tck.model.contributing.PredefinedClassesConfigModel; +import org.graalvm.internal.tck.model.contributing.ResourceConfigModel; +import org.graalvm.internal.tck.model.contributing.Question; +import org.graalvm.internal.tck.model.contributing.SerializationConfigModel; +import org.graalvm.internal.tck.utils.ConfigurationStringBuilder; +import org.graalvm.internal.tck.utils.FilesUtils; +import org.graalvm.internal.tck.utils.InteractiveTaskUtils; +import org.gradle.api.DefaultTask; +import org.gradle.api.tasks.TaskAction; +import org.gradle.process.ExecOperations; + +import javax.inject.Inject; +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.*; + +public abstract class ContributionTask extends DefaultTask { + private static final String METADATA_INDEX = "metadata/index.json"; + private static final String BUILD_FILE = "build.gradle"; + private static final String USER_CODE_FILTER_FILE = "user-code-filter.json"; + private static final String REQUIRED_DOCKER_IMAGES_FILE = "required-docker-images.txt"; + @Inject + protected abstract ExecOperations getExecOperations(); + + private final ObjectMapper objectMapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT).setSerializationInclusion(JsonInclude.Include.NON_NULL); + + private Path testsDirectory; + private Path metadataDirectory; + + private Coordinates coordinates; + + private record ContributingQuestion(String question, String help) {} + private final Map questions = new HashMap<>(); + + private void initializeWorkingDirectories(){ + testsDirectory = Path.of(getProject().file(CoordinateUtils.replace("tests/src/$group$/$artifact$/$version$", coordinates)).getAbsolutePath()); + metadataDirectory = Path.of(getProject().file(CoordinateUtils.replace("metadata/$group$/$artifact$/$version$", coordinates)).getAbsolutePath()); + } + + private void loadQuestions() throws IOException { + File questionsJson = getProject().file("tests/tck-build-logic/src/main/resources/contributing/questions.json"); + List contributingQuestions = objectMapper.readValue(questionsJson, new TypeReference<>() {}); + for (var question : contributingQuestions) { + this.questions.put(question.questionKey(), new ContributingQuestion(question.question(), question.help())); + } + } + + @TaskAction + void run() throws IOException { + InteractiveTaskUtils.printUserInfo("Hello! This task will help you contributing to metadata repository." + + " Please answer the following contributingQuestions. In case you don't know the answer on the question, type \"help\" for more information"); + + loadQuestions(); + + this.coordinates = getCoordinates(); + InteractiveTaskUtils.closeSection(); + + Path coordinatesMetadataRoot = getProject().file(CoordinateUtils.replace("metadata/$group$/$artifact$", coordinates)).toPath(); + boolean isExistingLibrary = Files.exists(coordinatesMetadataRoot); + + Path testsLocation = getTestsLocation(); + InteractiveTaskUtils.closeSection(); + + Path resourcesLocation = getResourcesLocation(); + InteractiveTaskUtils.closeSection(); + + List dockerImages = getDockerImages(); + InteractiveTaskUtils.closeSection(); + + List packages = getAllowedPackages(); + InteractiveTaskUtils.closeSection(); + + List additionalTestImplementationDependencies = getAdditionalDependencies(); + InteractiveTaskUtils.closeSection(); + + // initialize project + initializeWorkingDirectories(); + createStubs(isExistingLibrary); + updateAllowedPackages(packages); + + // generate necessary infrastructure + addTests(testsLocation); + addResources(resourcesLocation); + addDockerImages(dockerImages); + addUserCodeFilterFile(packages); + addAdditionalDependencies(additionalTestImplementationDependencies); + addAgentConfigBlock(); + + // run agent in conditional mode + collectMetadata(); + + // remove empty files + removeEmptyConfigFiles(); + + // create a PR + boolean shouldCreatePR = shouldCreatePullRequest(); + if (shouldCreatePR) { + String branch = "add-support-for-" + coordinates.toString().replace(':', '-'); + createPullRequest(branch); + + InteractiveTaskUtils.printUserInfo("Please update the pull request description to mention all places where your pull request" + + "accesses files, network, docker, or any other external service, and check if all checks in the description are correctly marked"); + } + + InteractiveTaskUtils.printSuccessfulStatement("Contribution successfully completed! Thank you!"); + } + + private Coordinates getCoordinates() { + ContributingQuestion question = questions.get("coordinates"); + return InteractiveTaskUtils.askQuestion(question.question(), question.help(), (answer) -> { + String[] coordinatesParts = answer.split(":"); + if (coordinatesParts.length != 3) { + throw new IllegalStateException("Maven coordinates not provided in the correct format. Type help for explanation."); + } + + String group = coordinatesParts[0]; + String artifact = coordinatesParts[1]; + String version = coordinatesParts[2]; + return new Coordinates(group, artifact, version); + }); + } + + private Path getTestsLocation() { + ContributingQuestion question = questions.get("testsLocation"); + return InteractiveTaskUtils.askQuestion(question.question(), question.help(), (answer) -> { + Path testsLocation = Path.of(answer).toAbsolutePath(); + if (!Files.exists(testsLocation)) { + throw new IllegalStateException("Cannot find tests directory on the given location: " + testsLocation + ". Type help for explanation."); + } + + if (!Files.isDirectory(testsLocation)) { + throw new IllegalStateException("Provided path does not represent a directory: " + testsLocation + ". Type help for explanation."); + } + + checkPackages(testsLocation); + + return testsLocation; + }); + } + + private void checkPackages(Path testsPath) { + List javaFiles = new ArrayList<>(); + FilesUtils.findJavaFiles(testsPath, javaFiles); + javaFiles.forEach(file -> { + try { + Optional packageLine = Files.readAllLines(file).stream().filter(line -> line.contains("package ")).findFirst(); + if (packageLine.isEmpty()) { + throw new RuntimeException("Java file: " + file + " does not contain declared package"); + } + + String declaredPackage = packageLine.get().split(" ")[1].replace(";", ""); + String packagePath = declaredPackage.replace(".", File.separator); + if (!Files.exists(testsPath.resolve(packagePath))) { + throw new IllegalStateException("File: " + file + " has package: " + declaredPackage + + " that cannot be found on tests location: " + testsPath + + ". Please make sure that the location you provided is a directory that contains packages with tests implementations"); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } + + private Path getResourcesLocation(){ + ContributingQuestion question = questions.get("resourcesLocation"); + return InteractiveTaskUtils.askQuestion(question.question(), question.help(), (answer) -> { + if (answer.equalsIgnoreCase("-")) { + return null; + } + + Path resourcesLocation = Path.of(answer).toAbsolutePath(); + if (!Files.exists(resourcesLocation)) { + throw new IllegalStateException("Cannot find resources directory on the given location: " + resourcesLocation + ". Type help for explanation."); + } + + if (!Files.isDirectory(resourcesLocation)) { + throw new IllegalStateException("Provided path does not represent a directory: " + resourcesLocation + ". Type help for explanation."); + } + + return resourcesLocation; + }); + } + + private List getDockerImages() { + ContributingQuestion question = questions.get("docker"); + + List images = new ArrayList<>(); + while (true) { + String nextImage = InteractiveTaskUtils.askQuestion(question.question(), question.help(), answer -> { + if (!answer.equalsIgnoreCase("-") && answer.split(":").length != 2) { + throw new IllegalStateException("Docker image name not provided in the correct format. Type help for explanation."); + } + + return answer; + }); + + if (nextImage.trim().equalsIgnoreCase("-")) { + break; + } + + images.add(nextImage); + } + + return images; + } + + private List getAllowedPackages() { + ContributingQuestion question = questions.get("allowedPackages"); + List packages = new ArrayList<>(); + while (true) { + String nextPackage = InteractiveTaskUtils.askQuestion(question.question(), question.help(), answer -> answer); + if (nextPackage.trim().equalsIgnoreCase("-")) { + if (packages.isEmpty()) { + InteractiveTaskUtils.printErrorMessage("At least one package must be provided. Type help for explanation."); + continue; + } + + break; + } + + packages.add(nextPackage); + } + + return packages; + } + + private List getAdditionalDependencies() { + ContributingQuestion question = questions.get("additionalDependencies"); + List dependencies = new ArrayList<>(); + while (true) { + Coordinates dependency = InteractiveTaskUtils.askQuestion(question.question(), question.help(), answer -> { + if (answer.equalsIgnoreCase("-")) { + return null; + } + + String[] coordinatesParts = answer.split(":"); + if (coordinatesParts.length != 3) { + throw new IllegalStateException("Maven coordinates not provided in the correct format. Type help for explanation."); + } + + String group = coordinatesParts[0]; + String artifact = coordinatesParts[1]; + String version = coordinatesParts[2]; + return new Coordinates(group, artifact, version); + }); + + if (dependency == null) { + break; + } + + dependencies.add(dependency); + } + + return dependencies; + } + + private void createStubs(boolean shouldUpdate){ + InteractiveTaskUtils.printUserInfo("Generating stubs for: " + coordinates ); + if (shouldUpdate) { + invokeCommand("gradle scaffold --coordinates " + coordinates + " --update", "Cannot generate stubs for: " + coordinates); + } else { + invokeCommand("gradle scaffold --coordinates " + coordinates, "Cannot generate stubs for: " + coordinates); + } + } + + private void updateAllowedPackages(List allowedPackages) throws IOException { + InteractiveTaskUtils.printUserInfo("Updating allowed packages in: " + METADATA_INDEX); + File metadataIndex = getProject().file(METADATA_INDEX); + + List entries = objectMapper.readValue(metadataIndex, new TypeReference<>() {}); + int replaceEntryIndex = -1; + for (int i = 0; i < entries.size(); i++) { + if (entries.get(i).module().equals(coordinates.group() + ":" + coordinates.artifact())) { + replaceEntryIndex = i; + } + } + + if (replaceEntryIndex != -1) { + MetadataIndexEntry replacedEntry = entries.remove(replaceEntryIndex); + Set extendedAllowedPackages = new HashSet<>(replacedEntry.allowedPackages()); + extendedAllowedPackages.addAll(allowedPackages); + + entries.add(new MetadataIndexEntry(replacedEntry.directory(), replacedEntry.module(), replacedEntry.requires(), new ArrayList<>(extendedAllowedPackages))); + } + + List sortedEntries = entries.stream() + .sorted(Comparator.comparing(MetadataIndexEntry::module)) + .toList(); + + objectMapper.writeValue(metadataIndex, sortedEntries); + } + + private void addTests(Path originalTestsLocation){ + Path destination = testsDirectory.resolve("src") + .resolve("test") + .resolve("java"); + Path allTests = originalTestsLocation.resolve("."); + + InteractiveTaskUtils.printUserInfo("Removing dummy test stubs"); + invokeCommand("rm -r " + destination, "Cannot delete files from: " + destination); + + InteractiveTaskUtils.printUserInfo("Copying tests from: " + originalTestsLocation + " to " + destination); + invokeCommand("cp -a " + allTests + " " + destination, "Cannot copy files to: " + destination); + } + + private void addResources(Path originalResourcesDirectory){ + if (originalResourcesDirectory == null) { + return; + } + + Path destination = testsDirectory.resolve("src").resolve("test"); + InteractiveTaskUtils.printUserInfo("Copying resources from: " + originalResourcesDirectory + " to " + destination); + + invokeCommand("cp -r " + originalResourcesDirectory + " " + destination, "Cannot copy files to: " + destination); + } + + private void addDockerImages(List images) throws IOException { + if (images.isEmpty()) { + return; + } + + InteractiveTaskUtils.printUserInfo("Adding following docker images to " + REQUIRED_DOCKER_IMAGES_FILE + ": " + images); + Path destination = testsDirectory.resolve(REQUIRED_DOCKER_IMAGES_FILE); + if (!Files.exists(destination)) { + Files.createFile(destination); + } + + for (var image : images) { + writeToFile(destination, image.concat("\n"), StandardOpenOption.APPEND); + } + } + + private void addUserCodeFilterFile(List packages) throws IOException { + InteractiveTaskUtils.printUserInfo("Generating " + USER_CODE_FILTER_FILE); + + ConfigurationStringBuilder sb = new ConfigurationStringBuilder(); + sb.openObject().newLine(); + sb.indent(); + sb.quote("rules").separateWithSemicolon().openArray().newLine(); + sb.indent(); + sb.openObject().appendStringProperty("excludeClasses", "**").closeObject().concat().newLine(); + for (int i = 0; i < packages.size(); i++) { + String nextPackage = packages.get(i) + ".**"; + sb.openObject().appendStringProperty("includeClasses", nextPackage).closeObject(); + if (i < packages.size() - 1) { + sb.concat(); + } + + sb.newLine(); + } + + sb.unindent(); + sb.closeArray().newLine(); + sb.unindent(); + sb.closeObject(); + + writeToFile(testsDirectory.resolve(USER_CODE_FILTER_FILE), sb.toString(), StandardOpenOption.CREATE); + } + + private void addAdditionalDependencies(List dependencies) { + if (dependencies == null) { + return; + } + + Path buildFilePath = testsDirectory.resolve(BUILD_FILE); + InteractiveTaskUtils.printUserInfo("Adding following dependencies to " + BUILD_FILE + " file: " + dependencies); + + if (!Files.exists(buildFilePath) || !Files.isRegularFile(buildFilePath)) { + throw new RuntimeException("Cannot add additional dependencies to " + buildFilePath + ". Please check if a " + BUILD_FILE + " exists on that location."); + } + + try { + ConfigurationStringBuilder sb = new ConfigurationStringBuilder(); + List content = Files.readAllLines(buildFilePath); + for (var line : content) { + sb.append(line).newLine(); + if (line.trim().equalsIgnoreCase("dependencies {")) { + sb.indent(); + for (var dependency : dependencies) { + sb.append("testImplementation").space().quote(dependency.toString()).newLine(); + } + sb.unindent(); + } + } + + writeToFile(buildFilePath, sb.toString(), StandardOpenOption.WRITE); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void addAgentConfigBlock() { + Path buildFilePath = testsDirectory.resolve(BUILD_FILE); + InteractiveTaskUtils.printUserInfo("Configuring agent block in: " + BUILD_FILE); + + if (!Files.exists(buildFilePath) || !Files.isRegularFile(buildFilePath)) { + throw new RuntimeException("Cannot add additional dependencies to " + buildFilePath + ". Please check if a " + BUILD_FILE + " exists on that location."); + } + + + try(InputStream stream = ContributionTask.class.getResourceAsStream("/contributing/agent.template")) { + if (stream == null) { + throw new RuntimeException("Cannot find template for the graalvm configuration block"); + } + + String content = "\n" + (new String(stream.readAllBytes(), StandardCharsets.UTF_8)); + writeToFile(buildFilePath, content, StandardOpenOption.APPEND); + } catch (IOException e) { + throw new RuntimeException("Cannot add agent block into: " + buildFilePath); + } + } + + private void collectMetadata() { + InteractiveTaskUtils.printUserInfo("Generating metadata"); + invokeCommand("gradle -Pagent test", "Cannot generate metadata", testsDirectory); + + InteractiveTaskUtils.printUserInfo("Performing metadata copy"); + invokeCommand("gradle metadataCopy --task test --dir " + metadataDirectory, "Cannot perform metadata copy", testsDirectory); + } + + private enum CONFIG_FILES { + RESOURCE("resource-config.json"), + REFLECTION("reflect-config.json"), + SERIALIZATION("serialization-config.json"), + JNI("jni-config.json"), + PROXY("proxy-config.json"), + PREDEFINED_CLASSES("predefined-classes-config.json"); + + private final String value; + public String get() { + return value; + } + + CONFIG_FILES(String val) { + this.value = val; + } + } + + private void removeEmptyConfigFiles() throws IOException { + Path indexFile = metadataDirectory.resolve("index.json"); + List remainingFiles = new LinkedList<>(Arrays.asList(CONFIG_FILES.values())); + + Path resourceConfigPath = metadataDirectory.resolve(CONFIG_FILES.RESOURCE.get()); + ResourceConfigModel resourceConfig = objectMapper.readValue(new File(resourceConfigPath.toUri()), new TypeReference<>() {}); + if (resourceConfig.bundles().isEmpty() && resourceConfig.resources().toString().equalsIgnoreCase("{}")) { + removeConfigFile(resourceConfigPath, CONFIG_FILES.RESOURCE, remainingFiles); + } + + Path serializationConfigPath = metadataDirectory.resolve(CONFIG_FILES.SERIALIZATION.get()); + SerializationConfigModel serializationConfig = objectMapper.readValue(new File(serializationConfigPath.toUri()), new TypeReference<>() {}); + if (serializationConfig.lambdaCapturingTypes().isEmpty() && serializationConfig.types().isEmpty() && serializationConfig.proxies().isEmpty()) { + removeConfigFile(serializationConfigPath, CONFIG_FILES.SERIALIZATION, remainingFiles); + } + + Path jniConfigPath = metadataDirectory.resolve(CONFIG_FILES.JNI.get()); + List jniConfig = objectMapper.readValue(new File(jniConfigPath.toUri()), new TypeReference<>() {}); + if (jniConfig.isEmpty()) { + removeConfigFile(jniConfigPath, CONFIG_FILES.JNI, remainingFiles); + } + + Path proxyConfigPath = metadataDirectory.resolve(CONFIG_FILES.PROXY.get()); + List proxyConfig = objectMapper.readValue(new File(proxyConfigPath.toUri()), new TypeReference<>() {}); + if (proxyConfig.isEmpty()) { + removeConfigFile(proxyConfigPath, CONFIG_FILES.PROXY, remainingFiles); + } + + Path reflectConfigPath = metadataDirectory.resolve(CONFIG_FILES.REFLECTION.get()); + List reflectConfig = objectMapper.readValue(new File(reflectConfigPath.toUri()), new TypeReference<>() {}); + if (reflectConfig.isEmpty()) { + removeConfigFile(reflectConfigPath, CONFIG_FILES.REFLECTION, remainingFiles); + } + + Path predefinedClassesConfigPath = metadataDirectory.resolve(CONFIG_FILES.PREDEFINED_CLASSES.get()); + List predefinedClassesConfig = objectMapper.readValue(new File(predefinedClassesConfigPath.toUri()), new TypeReference<>() {}); + if (predefinedClassesConfig.size() == 1) { + if (predefinedClassesConfig.get(0).type().equalsIgnoreCase("agent-extracted") && predefinedClassesConfig.get(0).classes().isEmpty()) { + removeConfigFile(predefinedClassesConfigPath, CONFIG_FILES.PREDEFINED_CLASSES, remainingFiles); + } + } + + Path agentExtractedPredefinedClasses = metadataDirectory.resolve("agent-extracted-predefined-classes"); + if (Files.exists(agentExtractedPredefinedClasses)) { + File[] extractedPredefinedClasses = new File(agentExtractedPredefinedClasses.toUri()).listFiles(); + if (extractedPredefinedClasses == null || extractedPredefinedClasses.length == 0) { + InteractiveTaskUtils.printUserInfo("Removing empty: agent-extracted-predefined-classes"); + invokeCommand("rm -r " + agentExtractedPredefinedClasses, "Cannot delete empty config file: " + agentExtractedPredefinedClasses); + } + } + + trimIndexFile(indexFile, remainingFiles); + } + + private void removeConfigFile(Path path, CONFIG_FILES file, List remainingFiles) { + InteractiveTaskUtils.printUserInfo("Removing empty: " + file.get()); + invokeCommand("rm " + path, "Cannot delete empty config file: " + path); + remainingFiles.remove(file); + } + + private void trimIndexFile(Path index, List remainingFiles) throws IOException { + InteractiveTaskUtils.printUserInfo("Removing sufficient entries from: " + index); + ConfigurationStringBuilder sb = new ConfigurationStringBuilder(); + sb.openArray().newLine(); + sb.indent(); + for (int i = 0; i < remainingFiles.size(); i++) { + sb.quote(remainingFiles.get(i).get()); + + if (i != remainingFiles.size() - 1) { + sb.concat(); + } + + sb.newLine(); + } + + sb.unindent(); + sb.closeArray(); + + writeToFile(index, sb.toString(), StandardOpenOption.TRUNCATE_EXISTING); + } + + private boolean shouldCreatePullRequest() { + ContributingQuestion question = questions.get("shouldCreatePullRequest"); + return InteractiveTaskUtils.askYesNoQuestion(question.question(), question.help(), true); + } + + private void createPullRequest(String branch) { + InteractiveTaskUtils.printUserInfo("Creating new branch: " + branch); + invokeCommand("git switch -C " + branch, "Cannot create a new branch"); + + InteractiveTaskUtils.printUserInfo("Staging changes"); + invokeCommand("git add .", "Cannot add changes"); + + InteractiveTaskUtils.printUserInfo("Committing changes"); + invokeCommand("git", List.of("commit", "-m", "Add metadata for " + coordinates), "Cannot commit changes", null); + + InteractiveTaskUtils.printUserInfo("Pushing changes"); + invokeCommand("git push origin " + branch, "Cannot push to origin"); + + InteractiveTaskUtils.printUserInfo("Complete pull request creation on the above link"); + } + + private void writeToFile(Path path, String content, StandardOpenOption writeOption) throws IOException { + Files.createDirectories(path.getParent()); + Files.writeString(path, content, StandardCharsets.UTF_8, writeOption); + } + + private void invokeCommand(String command, String errorMessage) { + invokeCommand(command, errorMessage, null); + } + + private void invokeCommand(String command, String errorMessage, Path workingDirectory) { + String[] commandParts = command.split(" "); + String executable = commandParts[0]; + + List args = List.of(Arrays.copyOfRange(commandParts, 1, commandParts.length)); + invokeCommand(executable, args, errorMessage, workingDirectory); + } + + private void invokeCommand(String executable, List args, String errorMessage, Path workingDirectory) { + ByteArrayOutputStream execOutput = new ByteArrayOutputStream(); + var result = getExecOperations().exec(execSpec -> { + if (workingDirectory != null) { + execSpec.setWorkingDir(workingDirectory); + } + execSpec.setExecutable(executable); + execSpec.setArgs(args); + execSpec.setStandardOutput(execOutput); + }); + + if (result.getExitValue() != 0) { + throw new RuntimeException(errorMessage + ". See: " + execOutput); + } + } +} diff --git a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/GrypeTask.java b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/GrypeTask.java index a1b554789..c17203ded 100644 --- a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/GrypeTask.java +++ b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/GrypeTask.java @@ -10,7 +10,6 @@ import java.net.URISyntaxException; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.nio.file.Paths; import java.util.*; import static org.graalvm.internal.tck.DockerUtils.extractImagesNames; diff --git a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/ScaffoldTask.java b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/ScaffoldTask.java index 6962a784f..2c5650d26 100644 --- a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/ScaffoldTask.java +++ b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/ScaffoldTask.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import org.graalvm.internal.tck.model.MetadataIndexEntry; +import org.graalvm.internal.tck.model.MetadataVersionsIndexEntry; import org.graalvm.internal.tck.model.TestIndexEntry; import org.gradle.api.DefaultTask; import org.gradle.api.logging.LogLevel; @@ -36,6 +37,7 @@ class ScaffoldTask extends DefaultTask { private String coordinates; private boolean force; + private boolean update; public ScaffoldTask() { } @@ -55,6 +57,12 @@ void setForce(boolean force) { this.force = force; } + + @Option(option = "update", description = "Add metadata for new version of library that already exists in the repository") + void setUpdate(boolean update) { + this.update = update; + } + @TaskAction void run() throws IOException { Coordinates coordinates = Coordinates.parse(this.coordinates); @@ -63,13 +71,19 @@ void run() throws IOException { Path coordinatesMetadataVersionRoot = coordinatesMetadataRoot.resolve(coordinates.version()); Path coordinatesTestRoot = getProject().file(CoordinateUtils.replace("tests/src/$group$/$artifact$/$version$", coordinates)).toPath(); - checkExistingMetadata(coordinates, coordinatesMetadataRoot, coordinatesMetadataVersionRoot); - // Metadata - writeCoordinatesMetadataRootJson(coordinatesMetadataRoot, coordinates); + if (!update) { + checkExistingMetadata(coordinates, coordinatesMetadataRoot, coordinatesMetadataVersionRoot); + writeCoordinatesMetadataRootJson(coordinatesMetadataRoot, coordinates); + } else { + updateCoordinatesMetadataRootJson(coordinatesMetadataRoot, coordinates); + } + writeCoordinatesMetadataVersionJsons(coordinatesMetadataVersionRoot, coordinates); addToMetadataIndexJson(coordinates); + + // Tests writeTestScaffold(coordinatesTestRoot, coordinates); addToTestIndexJson(coordinates); @@ -229,6 +243,45 @@ private void writeCoordinatesMetadataRootJson(Path metadataRoot, Coordinates coo ); } + private void updateCoordinatesMetadataRootJson(Path metadataRoot, Coordinates coordinates) throws IOException { + File metadataIndex = metadataRoot.resolve("index.json").toFile(); + List entries = objectMapper.readValue(metadataIndex, new TypeReference<>() {}); + int deleteIndex = -1; + for (int i = 0; i < entries.size(); i++) { + MetadataVersionsIndexEntry nextEntry = entries.get(i); + if (nextEntry.latest() == null || nextEntry.latest()) { + deleteIndex = i; + } + } + + // replace entry that was previously marked with latest: true + if (deleteIndex != -1) { + MetadataVersionsIndexEntry deletedEntry = entries.remove(deleteIndex); + MetadataVersionsIndexEntry replaceEntry = new MetadataVersionsIndexEntry(null, + deletedEntry.override(), + deletedEntry.module(), + deletedEntry.defaultFor(), + deletedEntry.metadataVersion(), + deletedEntry.testedVersions()); + entries.add(replaceEntry); + } + + // create new latest entry + MetadataVersionsIndexEntry newEntry = new MetadataVersionsIndexEntry(true, + null, + coordinates.group() + ":" + coordinates.artifact(), + null, + coordinates.version(), + List.of(coordinates.version())); + + entries.add(newEntry); + List sortedEntries = entries.stream() + .sorted(Comparator.comparing(MetadataVersionsIndexEntry::module)) + .toList(); + + objectMapper.writeValue(metadataIndex, sortedEntries); + } + private String getEmptyJsonArray() { return "[]\n"; } diff --git a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/model/contributing/PredefinedClassesConfigModel.java b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/model/contributing/PredefinedClassesConfigModel.java new file mode 100644 index 000000000..12c0da3b6 --- /dev/null +++ b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/model/contributing/PredefinedClassesConfigModel.java @@ -0,0 +1,9 @@ +package org.graalvm.internal.tck.model.contributing; + +import java.util.List; + +public record PredefinedClassesConfigModel( + String type, + List classes +) { +} diff --git a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/model/contributing/Question.java b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/model/contributing/Question.java new file mode 100644 index 000000000..62207ecc7 --- /dev/null +++ b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/model/contributing/Question.java @@ -0,0 +1,15 @@ +package org.graalvm.internal.tck.model.contributing; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/* + * JSON model for metadata/index.json. + */ +public record Question( + @JsonProperty("question-key") + String questionKey, + String question, + + String help +) { +} diff --git a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/model/contributing/ResourceConfigModel.java b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/model/contributing/ResourceConfigModel.java new file mode 100644 index 000000000..d24fd73a9 --- /dev/null +++ b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/model/contributing/ResourceConfigModel.java @@ -0,0 +1,8 @@ +package org.graalvm.internal.tck.model.contributing; +import java.util.List; + +public record ResourceConfigModel( + Object resources, + List bundles +) { +} diff --git a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/model/contributing/SerializationConfigModel.java b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/model/contributing/SerializationConfigModel.java new file mode 100644 index 000000000..3d0b1e2b1 --- /dev/null +++ b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/model/contributing/SerializationConfigModel.java @@ -0,0 +1,11 @@ +package org.graalvm.internal.tck.model.contributing; + + +import java.util.List; + +public record SerializationConfigModel( + List types, + List proxies, + List lambdaCapturingTypes +) { +} diff --git a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/utils/ColoredOutput.java b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/utils/ColoredOutput.java new file mode 100644 index 000000000..34898f16b --- /dev/null +++ b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/utils/ColoredOutput.java @@ -0,0 +1,30 @@ +package org.graalvm.internal.tck.utils; + +public class ColoredOutput { + + public enum OUTPUT_COLOR { + RED("\u001B[31m"), + GREEN("\u001B[32m"), + BLUE("\u001B[34m"), + YELLOW("\u001B[33m"), + WHITE("\u001B[37m"); + + private final String colorCode; + + OUTPUT_COLOR(String color) { + this.colorCode = color; + } + + @Override + public String toString() { + return this.colorCode; + } + } + + private static final String ANSI_RESET = "\u001B[0m"; + + public static void println(String message, OUTPUT_COLOR color) { + System.out.println(color + message + ANSI_RESET); + } + +} diff --git a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/utils/ConfigurationStringBuilder.java b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/utils/ConfigurationStringBuilder.java new file mode 100644 index 000000000..6f45a240b --- /dev/null +++ b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/utils/ConfigurationStringBuilder.java @@ -0,0 +1,103 @@ +package org.graalvm.internal.tck.utils; + +public class ConfigurationStringBuilder { + + private final StringBuilder sb; + private int indentationLevel; + + private boolean startedNewLine; + + public ConfigurationStringBuilder() { + this.sb = new StringBuilder(); + this.indentationLevel = 0; + this.startedNewLine = false; + } + + + public ConfigurationStringBuilder append(String content) { + if (startedNewLine) { + sb.append("\t".repeat(Math.max(0, indentationLevel))); + } + sb.append(content); + startedNewLine = false; + + return this; + } + + public ConfigurationStringBuilder newLine() { + this.append("\n"); + startedNewLine = true; + + return this; + } + + public ConfigurationStringBuilder indent() { + indentationLevel++; + return this; + } + + public ConfigurationStringBuilder unindent() { + if (indentationLevel > 0) { + indentationLevel--; + } + + return this; + } + + public ConfigurationStringBuilder openObject() { + return this.append("{"); + } + + public ConfigurationStringBuilder closeObject() { + return this.append("}"); + } + + public ConfigurationStringBuilder openArray() { + return this.append("["); + } + + public ConfigurationStringBuilder closeArray() { + return this.append("]"); + } + + public ConfigurationStringBuilder space() { + return this.append(" "); + } + + public ConfigurationStringBuilder concat() { + return this.append(","); + } + + public ConfigurationStringBuilder separateWithSemicolon() { + return this.append(": "); + } + + public ConfigurationStringBuilder separateWithEquals() { + return this.append(" = "); + } + + public ConfigurationStringBuilder quote(String text) { + return this.append("\"").append(text).append("\""); + } + + public ConfigurationStringBuilder putInBrackets(String text) { + return this.append("(").append(text).append(")"); + } + + public ConfigurationStringBuilder quoteInBrackets(String text) { + return this.append("(").quote(text).append(")"); + } + + public ConfigurationStringBuilder appendStringProperty(String key, String value) { + return this.quote(key).separateWithSemicolon().quote(value); + } + + public ConfigurationStringBuilder appendAssignedVariable(String variable, String value) { + return this.append(variable).separateWithEquals().quote(value); + } + + @Override + public String toString() { + return sb.toString(); + } +} diff --git a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/utils/FilesUtils.java b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/utils/FilesUtils.java new file mode 100644 index 000000000..bc645639c --- /dev/null +++ b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/utils/FilesUtils.java @@ -0,0 +1,27 @@ +package org.graalvm.internal.tck.utils; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +public class FilesUtils { + + public static void findJavaFiles(Path root, List result) { + if (Files.exists(root) && Files.isRegularFile(root) && root.toString().endsWith(".java")) { + result.add(root); + return; + } + + if (Files.isDirectory(root)) { + File[] content = root.toFile().listFiles(); + if (content == null) { + return; + } + + for (var file : content) { + findJavaFiles(file.toPath(), result); + } + } + } +} diff --git a/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/utils/InteractiveTaskUtils.java b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/utils/InteractiveTaskUtils.java new file mode 100644 index 000000000..e4b73ebb3 --- /dev/null +++ b/tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/utils/InteractiveTaskUtils.java @@ -0,0 +1,91 @@ +package org.graalvm.internal.tck.utils; + +import java.util.Scanner; +import java.util.function.Function; + +public class InteractiveTaskUtils { + public static R askQuestion(String question, String helpMessage, Function handleAnswer) { + Scanner scanner = new Scanner(System.in); + + while (true) { + printQuestion(question); + + String answer = scanner.next(); + if (answer.equalsIgnoreCase("help")) { + printHelpMessage(helpMessage); + continue; + } + + try { + return handleAnswer.apply(answer); + } catch (IllegalStateException ex) { + printErrorMessage(ex.getMessage()); + } + } + } + + public static boolean askYesNoQuestion(String question, String helpMessage, boolean defaultAnswer) { + Scanner scanner = new Scanner(System.in); + + while (true) { + printQuestion(question); + + String answer = scanner.nextLine(); + if (answer.equalsIgnoreCase("help")) { + printHelpMessage(helpMessage); + continue; + } + + if (answer.isEmpty()) { + return defaultAnswer; + } + + if (answer.equalsIgnoreCase("y")) { + return true; + } + + if (answer.equalsIgnoreCase("n")) { + return false; + } + + printErrorMessage("Your answer must be either y (for yes) or n (for no)"); + } + } + + public static void closeSection() { + ColoredOutput.println("------------------------------------------------------------------------------------------", ColoredOutput.OUTPUT_COLOR.BLUE); + } + + public static void printUserInfo(String message) { + ColoredOutput.println("[INFO] " + message + "...", ColoredOutput.OUTPUT_COLOR.BLUE); + waitForUserToReadMessage(); + } + + public static void printSuccessfulStatement(String message) { + ColoredOutput.println("[SUCCESS] " + message, ColoredOutput.OUTPUT_COLOR.GREEN); + waitForUserToReadMessage(); + } + + public static void printErrorMessage(String message) { + ColoredOutput.println("[ERROR] " + message, ColoredOutput.OUTPUT_COLOR.RED); + waitForUserToReadMessage(); + } + + public static void printHelpMessage(String helpMessage) { + ColoredOutput.println("[HELP] " + helpMessage, ColoredOutput.OUTPUT_COLOR.YELLOW); + waitForUserToReadMessage(); + } + + private static void printQuestion(String question) { + ColoredOutput.println("[QUESTION] " + question, ColoredOutput.OUTPUT_COLOR.GREEN); + } + + private static void waitForUserToReadMessage() { + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + throw new RuntimeException("Waiting for user to read the message was interrupted. Reason: " + e.getMessage()); + } + } + +} diff --git a/tests/tck-build-logic/src/main/resources/contributing/agent.template b/tests/tck-build-logic/src/main/resources/contributing/agent.template new file mode 100644 index 000000000..c388029dd --- /dev/null +++ b/tests/tck-build-logic/src/main/resources/contributing/agent.template @@ -0,0 +1,10 @@ +graalvmNative { + agent { + defaultMode = "conditional" + modes { + conditional { + userCodeFilterPath = "user-code-filter.json" + } + } + } +} diff --git a/tests/tck-build-logic/src/main/resources/contributing/empty-resource-config.json.template b/tests/tck-build-logic/src/main/resources/contributing/empty-resource-config.json.template new file mode 100644 index 000000000..29b2a7afb --- /dev/null +++ b/tests/tck-build-logic/src/main/resources/contributing/empty-resource-config.json.template @@ -0,0 +1,4 @@ +{ + "resources":{}, + "bundles":[] +} diff --git a/tests/tck-build-logic/src/main/resources/contributing/questions.json b/tests/tck-build-logic/src/main/resources/contributing/questions.json new file mode 100644 index 000000000..8a0a8b919 --- /dev/null +++ b/tests/tck-build-logic/src/main/resources/contributing/questions.json @@ -0,0 +1,37 @@ +[ + { + "question-key": "coordinates", + "question": "What library you want to support? Maven coordinates: ", + "help": "Maven coordinates consist of three parts in the following format \"groupId:artifactId:version\". For more information visit: https://maven.apache.org/repositories/artifacts.html" + }, + { + "question-key": "testsLocation", + "question": "Where are your tests implemented? Absolute path to the directory containing java packages where you implemented tests: ", + "help": "An absolute path to the directory that contains your tests. This path must be on your system and not some online location. Be aware that for all tests where you are not the sole author, you have to add a comment that proves that you may publish them under the specified license manually" + }, + { + "question-key": "resourcesLocation", + "question": "Do your tests need any kind of resources? Absolute path to the resources directory required for your tests (type \"-\" if resources are not required): ", + "help": "An absolute path to the directory that contains resources required for your tests. This path must be on your system and not some online location. " + }, + { + "question-key": "docker", + "question": "Do your tests use docker? Enter the next docker image name (to stop type \"-\"): ", + "help": "Enter the docker images (press enter after each image name you enter) that you want to use in your tests. Docker image declaration consists of two parts separated with \":\" in the following format: \"imageName:version\". When you finish adding docker images, type \"-\" to terminate the inclusion process" + }, + { + "question-key": "allowedPackages", + "question": "What package you want to include? Enter the next package (to stop type \"-\")", + "help": "Enter the packages (press enter after each package you entered) that you want to include in your metadata. When you finish adding packages, type \"-\" to terminate the inclusion process" + }, + { + "question-key": "additionalDependencies", + "question": "What additional testImplementation dependencies you want to include? Enter the next dependency (to stop type \"-\")", + "help": "Enter the testImplementation dependencies (pres enter after each dependency) you want to include use in tests. Provide dependencies in form of Maven coordinates. Maven coordinates consist of three parts in the following format \"groupId:artifactId:version\". For more information visit: https://maven.apache.org/repositories/artifacts.html When you finish adding dependencies, type \"-\" to terminate the inclusion process" + }, + { + "question-key": "shouldCreatePullRequest", + "question": "Do you want to create a pull request to the reachability metadata repository [Y/n]:", + "help": "In case you want to open a pull request to Reachability metadata repository automatically, type \"y\". This way the task will create a new branch for you, commit changes with a proper message, and push the branch remotly. At the end, the task will give you a link to the Github repository where you should fill in a pull request checkslist and complete the process." + } +]