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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions at-gradle/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,18 @@ gradlePlugin {
}
}

testing {
suites {
functionalTest(JvmTestSuite) {
useJUnitJupiter()
dependencies {
implementation project()
implementation gradleTestKit()
}
}
}
}

publishing {
repositories {
maven gradleutils.getPublishingForgeMaven(rootProject.file('../repo'))
Expand All @@ -106,3 +118,23 @@ publishing {
}
}
}

// We are not a module but unifying the sourcesets fixes pluginUnderTestMetadata producing the correct paths
sourceSets.each { sourceSet ->
sourceSet.output.resourcesDir = sourceSet.java.destinationDirectory = layout.projectDirectory.dir("bin/$sourceSet.name")
}

// We need to put the plugin metadata file on the resource path, because eclipse doesn't use gradle's build folder
sourceSets.functionalTest.resources.srcDirs += [ 'src/functionalTest/generated/' ]
tasks.named('pluginUnderTestMetadata') {
outputDirectory = file('src/functionalTest/generated/')
}
// We need to write the plugin info so that eclipse can find it without invoking gradle
sourceSets.main.resources.srcDirs += [ 'src/main/generated/' ]
tasks.named('pluginDescriptors') {
outputDirectory = file('src/main/generated/META-INF/gradle-plugins/')
}

eclipse {
synchronizationTasks pluginUnderTestMetadata, pluginDescriptors
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Copyright (c) Forge Development LLC
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.accesstransformers.gradle.tests;

import java.io.IOException;

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

public class FunctionalTests extends FunctionalTestsBase {
private static final String BUILD = ":build";

public FunctionalTests() {
super("9.0.0");
}

@Test
public void makeFieldAccessible() throws IOException {
makeFieldAccessible(new GroovyProject(projectDir));
}

@Test
public void makeFieldAccessibleKotlin() throws IOException {
makeFieldAccessible(new KotlinProject(projectDir));
}

private void makeFieldAccessible(GradleProject project) throws IOException {
project.transformDependency("org.apache.maven:maven-artifact:3.9.11", "transformer.cfg");
project.writeFile(
"transformer.cfg",
"public org.apache.maven.artifact.versioning.DefaultArtifactVersion majorVersion"
);
project.writeFile("src/java/Test.java", """
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;

public class Test {
public static void test() {
new DefaultArtifactVersion("0").majorVersion;
}
}
""");

var results = build(BUILD);
assertTaskSuccess(results, BUILD);
}

@Test
public void makeMethodAccessible() throws IOException {
makeMethodAccessible(new GroovyProject(projectDir));
}

@Test
public void makeMethodAccessibleKotlin() throws IOException {
makeMethodAccessible(new KotlinProject(projectDir));
}

private void makeMethodAccessible(GradleProject project) throws IOException {
project.transformDependency("org.ow2.asm:asm:9.7", "transformer.cfg");
writeMethodTest(project);

var results = build(BUILD);
assertTaskSuccess(results, BUILD);
}

@Test
@Disabled // I don't know what the point of the constraint system was so I don't have a good test
public void makeTransitiveAccessible() throws IOException {
makeTransitiveAccessible(new GroovyProject(projectDir));
}

@Test
@Disabled // I don't know what the point of the constraint system was so I don't have a good test
public void makeTransitiveAccessibleKotlin() throws IOException {
makeTransitiveAccessible(new KotlinProject(projectDir));
}

private void makeTransitiveAccessible(GradleProject project) throws IOException {
project.transformConstraint("org.ow2.asm:asm-tree:9.7", "org.ow2.asm:asm", "transformer.cfg");
writeMethodTest(project);

var results = build(BUILD);
assertTaskSuccess(results, BUILD);
}

private void writeMethodTest(GradleProject project) throws IOException {
project.writeFile(
"transformer.cfg",
"public org.objectweb.asm.Attribute <init>(Ljava/lang/String;)V"
);
project.writeFile("src/java/Test.java", """
import org.objectweb.asm.Attribute;

public class Test {
public static void test() {
new Attribute("123");
}
}
""");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright (c) Forge Development LLC
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.accesstransformers.gradle.tests;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.GradleRunner;
import org.gradle.testkit.runner.TaskOutcome;
import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.io.CleanupMode;
import org.junit.jupiter.api.io.TempDir;

import static org.junit.jupiter.api.Assertions.*;

public abstract class FunctionalTestsBase {
@TempDir(cleanup = CleanupMode.ON_SUCCESS)
protected Path projectDir;

@RegisterExtension
AfterTestExecutionCallback afterTestExecutionCallback = this::after;
private void after(ExtensionContext context) throws Exception {
if (context.getExecutionException().isPresent())
System.out.println(context.getDisplayName() + " Failed: " + projectDir);
}

protected final String gradleVersion;

protected FunctionalTestsBase(String gradleVersion) {
this.gradleVersion = gradleVersion;
}

protected void writeFile(Path file, String content) throws IOException {
Files.createDirectories(file.getParent());
Files.writeString(file, content, StandardCharsets.UTF_8);
}

protected GradleRunner runner(String... args) {
return GradleRunner.create()
.withGradleVersion(gradleVersion)
.withProjectDir(projectDir.toFile())
.withArguments(args)
.withPluginClasspath();
}

protected BuildResult build(String... args) {
return runner(args).build();
}

protected static void assertTaskSuccess(BuildResult result, String task) {
assertTaskOutcome(result, task, TaskOutcome.SUCCESS);
}

protected static void assertTaskFailed(BuildResult result, String task) {
assertTaskOutcome(result, task, TaskOutcome.FAILED);
}

protected static void assertTaskOutcome(BuildResult result, String task, TaskOutcome expected) {
var info = result.task(task);
assertNotNull(info, "Could not find task `" + task + "` in build results");
assertEquals(expected, info.getOutcome());
}

protected static byte[] readJarEntry(Path path, String name) throws IOException {
try (var fs = FileSystems.newFileSystem(path)) {
var target = fs.getPath(name);
assertTrue(Files.exists(target), "Archive " + path + " does not contain " + name);
return Files.readAllBytes(target);
}
}

protected static void assertFileMissing(Path path, String name) throws IOException {
try (var fs = FileSystems.newFileSystem(path)) {
var target = fs.getPath(name);
assertFalse(Files.exists(target), "Archive " + path + " contains `" + name + "` when it should not");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright (c) Forge Development LLC
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.accesstransformers.gradle.tests;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;

public abstract class GradleProject {
protected final Path projectDir;
protected final String buildFile;
protected final String settingsFile;

protected GradleProject(Path projectDir, String buildFile, String settingsFile) {
this.projectDir = projectDir;
this.buildFile = buildFile;
this.settingsFile = settingsFile;
}

protected static final String BASIC_SETTINGS = """
plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
}

rootProject.name = "test"
""";

protected void settingsFile() throws IOException {
settingsFile(BASIC_SETTINGS);
}

protected void settingsFile(String content) throws IOException {
writeFile(settingsFile, content);
}

protected static final String BASIC_BUILD = """
plugins {
id("java")
id("net.minecraftforge.accesstransformers")
}

repositories {
mavenCentral();
}
""";

protected void buildFile() throws IOException {
buildFile(BASIC_BUILD);
}

protected void buildFile(int javaVersion) throws IOException {
buildFile(BASIC_BUILD + javaVersion(javaVersion));
}

protected String javaVersion(int javaVersion) {
return "java.toolchain.languageVersion = JavaLanguageVersion.of(" + javaVersion + ")\n";
}

protected void buildFile(String content) throws IOException {
writeFile(buildFile, content);
}

public void writeFile(String name, String content) throws IOException {
writeFile(projectDir.resolve(name), content);
}

protected void writeFile(Path file, String content) throws IOException {
Files.createDirectories(file.getParent());
Files.writeString(file, content, StandardCharsets.UTF_8);
}

// Simple dependency transformation
// The test will write the config file, a java class which access the transformed field/method,
// Then attempt to run build.
protected abstract void transformDependency(String library, String config) throws IOException;

// Transform a transitive dependency using Gradle's constraints function.
// This allows you to transform the a dependency if it exists, but not have a hard reference
// to it in your metadata
// - I have no idea why you would do that - Lex
//
// The test will write the config file, a java class which access the transformed field/method,
// Then attempt to run ':build'.
protected abstract void transformConstraint(String library, String constraint, String config) throws IOException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (c) Forge Development LLC
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.accesstransformers.gradle.tests;

import java.io.IOException;
import java.nio.file.Path;

public class GroovyProject extends GradleProject {
protected GroovyProject(Path projectDir) {
super(projectDir, "build.gradle", "settings.gradle");
}

@Override
protected void transformDependency(String library, String config) throws IOException {
settingsFile();
buildFile(
BASIC_BUILD +
"""
dependencies {
implementation('{library}') {
accessTransformers.configure(it) {
config = project.file('{config}')
}
}
}
"""
.replace("{library}", library)
.replace("{config}", config)
);
}

@Override
protected void transformConstraint(String library, String constraint, String config) throws IOException {
settingsFile();
buildFile(
BASIC_BUILD +
"""
dependencies {
implementation('{library}')
constraints {
implementation('{constraint}') {
accessTransformers.configure(it) {
config = project.file('{config}')
}
}
}
}
"""
.replace("{library}", library)
.replace("{constraint}", constraint)
.replace("{config}", config)
);
}
}
Loading