Refactor and improve tests (#466)

* Install and run a production server in tests

* Small improvements

* Add FabricAPI build test
Create new GradleProjectTestTrait replacing the old trait
Improve groovy code formatting.

* Refactor tests

* Fix MultiProjectTest + fix logging for fabric api test

* Cleanup and fixes

* Update fabric api + run in parallel for speed

* Set server memory + fix error
dev/0.11
modmuss50 2021-08-31 11:48:58 +01:00 committed by GitHub
parent 2277b93f8d
commit 3ded0964c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 807 additions and 481 deletions

View File

@ -104,6 +104,7 @@ dependencies {
exclude module: 'groovy-all' exclude module: 'groovy-all'
} }
testImplementation 'io.javalin:javalin:3.13.9' testImplementation 'io.javalin:javalin:3.13.9'
testImplementation 'net.fabricmc:fabric-installer:0.7.4'
compileOnly 'org.jetbrains:annotations:21.0.1' compileOnly 'org.jetbrains:annotations:21.0.1'
} }

View File

@ -24,7 +24,7 @@ ruleset {
SpaceAfterSwitch SpaceAfterSwitch
SpaceAfterWhile SpaceAfterWhile
SpaceAroundClosureArrow SpaceAroundClosureArrow
SpaceAroundMapEntryColon SpaceAroundMapEntryColon(characterAfterColonRegex: /\ /)
SpaceAroundOperator SpaceAroundOperator
SpaceBeforeClosingBrace SpaceBeforeClosingBrace
SpaceBeforeOpeningBrace SpaceBeforeOpeningBrace
@ -61,6 +61,13 @@ ruleset {
FieldTypeRequired FieldTypeRequired
MethodParameterTypeRequired MethodParameterTypeRequired
// Imports
UnusedImport
UnnecessaryGroovyImport
NoWildcardImports(ignoreStaticImports: true)
ImportFromSamePackage
DuplicateImport
//Misc //Misc
LongLiteralWithLowerCaseL LongLiteralWithLowerCaseL
} }

View File

@ -29,6 +29,7 @@ import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -36,6 +37,7 @@ import java.util.stream.StreamSupport;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive; import com.google.gson.JsonPrimitive;
import org.gradle.api.Project; import org.gradle.api.Project;
@ -108,7 +110,13 @@ public final class MixinRefmapHelper {
@NotNull @NotNull
private static Collection<String> getMixinConfigurationFiles(JsonObject fabricModJson) { private static Collection<String> getMixinConfigurationFiles(JsonObject fabricModJson) {
return StreamSupport.stream(fabricModJson.getAsJsonArray("mixins").spliterator(), false) JsonArray mixins = fabricModJson.getAsJsonArray("mixins");
if (mixins == null) {
return Collections.emptyList();
}
return StreamSupport.stream(mixins.spliterator(), false)
.map(e -> { .map(e -> {
if (e instanceof JsonPrimitive str) { if (e instanceof JsonPrimitive str) {
return str.getAsString(); return str.getAsString();

View File

@ -54,7 +54,7 @@ public class MinecraftProcessedProvider extends MinecraftMappedProvider {
protected void addDependencies(DependencyInfo dependency, Consumer<Runnable> postPopulationScheduler) { protected void addDependencies(DependencyInfo dependency, Consumer<Runnable> postPopulationScheduler) {
if (jarProcessorManager.isInvalid(projectMappedJar) || isRefreshDeps()) { if (jarProcessorManager.isInvalid(projectMappedJar) || isRefreshDeps()) {
getProject().getLogger().info(":processing mapped jar"); getProject().getLogger().info(":processing mapped jar");
invalidateJars(); invalidateJar();
try { try {
FileUtils.copyFile(super.getMappedJar(), projectMappedJar); FileUtils.copyFile(super.getMappedJar(), projectMappedJar);
@ -69,16 +69,14 @@ public class MinecraftProcessedProvider extends MinecraftMappedProvider {
getProject().getDependencies().module("net.minecraft:minecraft-" + projectMappedClassifier + ":" + getMinecraftProvider().minecraftVersion() + "/" + getExtension().getMappingsProvider().mappingsIdentifier())); getProject().getDependencies().module("net.minecraft:minecraft-" + projectMappedClassifier + ":" + getMinecraftProvider().minecraftVersion() + "/" + getExtension().getMappingsProvider().mappingsIdentifier()));
} }
private void invalidateJars() { private void invalidateJar() {
File dir = projectMappedJar.getParentFile(); if (projectMappedJar.exists()) {
getProject().getLogger().warn("Invalidating project jar");
if (dir.exists()) {
getProject().getLogger().warn("Invalidating project jars");
try { try {
FileUtils.cleanDirectory(dir); FileUtils.forceDelete(projectMappedJar);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException("Failed to invalidate jars, try stopping gradle daemon or closing the game", e); throw new RuntimeException("Failed to invalidate jar, try stopping gradle daemon or closing the game", e);
} }
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* This file is part of fabric-loom, licensed under the MIT License (MIT). * This file is part of fabric-loom, licensed under the MIT License (MIT).
* *
* Copyright (c) 2016-2021 FabricMC * Copyright (c) 2021 FabricMC
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -22,25 +22,11 @@
* SOFTWARE. * SOFTWARE.
*/ */
package net.fabricmc.loom.test.util package net.fabricmc.loom.test
import org.zeroturnaround.zip.ZipUtil class LoomTestConstants {
public final static String DEFAULT_GRADLE = "7.0.1"
public final static String PRE_RELEASE_GRADLE = "7.3-20210827230026+0000"
trait ArchiveAssertionsTrait { public final static String[] STANDARD_TEST_VERSIONS = [DEFAULT_GRADLE, PRE_RELEASE_GRADLE]
String getArchiveEntry(String name, String entry, String project = "") {
def file = getOutputFile(name, project)
def bytes = ZipUtil.unpackEntry(file, entry)
if (bytes == null) {
throw new FileNotFoundException("Could not find ${entry} in ${name}")
}
new String(bytes as byte[])
}
boolean hasArchiveEntry(String name, String entry, String project = "") {
def file = getOutputFile(name, project)
ZipUtil.unpackEntry(file, entry) != null
}
} }

View File

@ -24,30 +24,25 @@
package net.fabricmc.loom.test.integration package net.fabricmc.loom.test.integration
import net.fabricmc.loom.test.util.ArchiveAssertionsTrait import net.fabricmc.loom.test.util.GradleProjectTestTrait
import net.fabricmc.loom.test.util.ProjectTestTrait
import spock.lang.Specification import spock.lang.Specification
import spock.lang.Unroll import spock.lang.Unroll
import static net.fabricmc.loom.test.LoomTestConstants.*
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
class AccessWidenerTest extends Specification implements ProjectTestTrait, ArchiveAssertionsTrait { class AccessWidenerTest extends Specification implements GradleProjectTestTrait {
@Override
String name() {
"accesswidener"
}
@Unroll @Unroll
def "accesswidener (gradle #gradle)"() { def "accesswidener (gradle #version)"() {
setup:
def gradle = gradleProject(project: "accesswidener", version: version)
when: when:
def result = create("build", gradle) def result = gradle.run(task: "build")
then: then:
result.task(":build").outcome == SUCCESS result.task(":build").outcome == SUCCESS
getArchiveEntry("fabric-example-mod-1.0.0.jar", "modid.accesswidener") == expected().replaceAll('\r', '') gradle.getOutputZipEntry("fabric-example-mod-1.0.0.jar", "modid.accesswidener") == expected().replaceAll('\r', '')
where: where:
gradle | _ version << STANDARD_TEST_VERSIONS
DEFAULT_GRADLE | _
PRE_RELEASE_GRADLE | _
} }
String expected() { String expected() {

View File

@ -24,42 +24,36 @@
package net.fabricmc.loom.test.integration package net.fabricmc.loom.test.integration
import net.fabricmc.loom.test.util.ProjectTestTrait import net.fabricmc.loom.test.util.GradleProjectTestTrait
import spock.lang.Specification import spock.lang.Specification
import spock.lang.Unroll import spock.lang.Unroll
import static net.fabricmc.loom.test.LoomTestConstants.*
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
class CustomManifestTest extends Specification implements ProjectTestTrait { class CustomManifestTest extends Specification implements GradleProjectTestTrait {
@Override
String name() {
"minimalBase"
}
@Override
def filesReady() {
buildGradle() << '''
loom {
customMinecraftManifest = "https://maven.fabricmc.net/net/minecraft/1_18_experimental-snapshot-1.json"
}
dependencies {
minecraft "com.mojang:minecraft:1.18_experimental-snapshot-1"
mappings "net.fabricmc:yarn:1.18_experimental-snapshot-1+build.2:v2"
modImplementation "net.fabricmc:fabric-loader:0.11.6"
}
'''
}
@Unroll @Unroll
def "customManifest (gradle #gradle)"() { def "customManifest (gradle #version)"() {
setup:
def gradle = gradleProject(project: "minimalBase", version: version)
gradle.buildGradle << '''
loom {
customMinecraftManifest = "https://maven.fabricmc.net/net/minecraft/1_18_experimental-snapshot-1.json"
}
dependencies {
minecraft "com.mojang:minecraft:1.18_experimental-snapshot-1"
mappings "net.fabricmc:yarn:1.18_experimental-snapshot-1+build.2:v2"
modImplementation "net.fabricmc:fabric-loader:0.11.6"
}
'''
when: when:
def result = create("build", gradle) def result = gradle.run(task: "build")
then: then:
result.task(":build").outcome == SUCCESS result.task(":build").outcome == SUCCESS
where: where:
gradle | _ version << STANDARD_TEST_VERSIONS
DEFAULT_GRADLE | _
PRE_RELEASE_GRADLE | _
} }
} }

View File

@ -24,28 +24,27 @@
package net.fabricmc.loom.test.integration package net.fabricmc.loom.test.integration
import net.fabricmc.loom.test.util.ProjectTestTrait import net.fabricmc.loom.test.util.GradleProjectTestTrait
import spock.lang.Specification import spock.lang.Specification
import spock.lang.Unroll import spock.lang.Unroll
import static net.fabricmc.loom.test.LoomTestConstants.*
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
class DecompileTest extends Specification implements ProjectTestTrait { class DecompileTest extends Specification implements GradleProjectTestTrait {
@Override
String name() {
"decompile"
}
@Unroll @Unroll
def "#decompiler gradle #gradle"() { def "#decompiler gradle #version"() {
setup:
def gradle = gradleProject(project: "decompile", version: version)
when: when:
def result = create(task, gradle) def result = gradle.run(task: task)
then: then:
result.task(":${task}").outcome == SUCCESS result.task(":${task}").outcome == SUCCESS
where: where:
decompiler | task | gradle decompiler | task | version
'fernflower' | "genSources" | DEFAULT_GRADLE 'fernflower' | "genSources" | DEFAULT_GRADLE
'fernflower' | "genSources" | PRE_RELEASE_GRADLE 'fernflower' | "genSources" | PRE_RELEASE_GRADLE
'cfr' | "genSourcesWithExperimentalCfr" | DEFAULT_GRADLE 'cfr' | "genSourcesWithExperimentalCfr" | DEFAULT_GRADLE

View File

@ -24,29 +24,27 @@
package net.fabricmc.loom.test.integration package net.fabricmc.loom.test.integration
import net.fabricmc.loom.test.util.ProjectTestTrait import net.fabricmc.loom.test.util.GradleProjectTestTrait
import spock.lang.Specification import spock.lang.Specification
import spock.lang.Unroll import spock.lang.Unroll
import static net.fabricmc.loom.test.LoomTestConstants.*
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
class DependencyResolutionManagementTest extends Specification implements ProjectTestTrait { class DependencyResolutionManagementTest extends Specification implements GradleProjectTestTrait {
@Override
String name() {
"dependencyResolutionManagement"
}
@Unroll @Unroll
def "build (gradle #gradle)"() { def "build (gradle #version)"() {
setup:
def gradle = gradleProject(project: "dependencyResolutionManagement", version: version)
when: when:
def result = create("build", gradle) def result = gradle.run(task: "build")
then: then:
result.task(":basic:build").outcome == SUCCESS result.task(":basic:build").outcome == SUCCESS
result.task(":projmap:build").outcome == SUCCESS result.task(":projmap:build").outcome == SUCCESS
where: where:
gradle | _ version << STANDARD_TEST_VERSIONS
DEFAULT_GRADLE | _
PRE_RELEASE_GRADLE | _
} }
} }

View File

@ -24,38 +24,34 @@
package net.fabricmc.loom.test.integration package net.fabricmc.loom.test.integration
import net.fabricmc.loom.test.util.ProjectTestTrait import net.fabricmc.loom.test.util.GradleProjectTestTrait
import spock.lang.Specification import spock.lang.Specification
import spock.lang.Unroll import spock.lang.Unroll
import static net.fabricmc.loom.test.LoomTestConstants.*
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
class ExperimentalVersionsTest extends Specification implements ProjectTestTrait { class ExperimentalVersionsTest extends Specification implements GradleProjectTestTrait {
@Override
String name() {
"minimalBase"
}
@Override
def filesReady() {
buildGradle() << '''
dependencies {
minecraft "com.mojang:minecraft:1.18_experimental-snapshot-1"
mappings "net.fabricmc:yarn:1.18_experimental-snapshot-1+build.2:v2"
modImplementation "net.fabricmc:fabric-loader:0.11.6"
}
'''
}
@Unroll @Unroll
def "experimental versions (gradle #gradle)"() { def "experimental versions (gradle #version)"() {
setup:
def gradle = gradleProject(project: "minimalBase", version: version)
gradle.buildGradle << '''
dependencies {
minecraft "com.mojang:minecraft:1.18_experimental-snapshot-1"
mappings "net.fabricmc:yarn:1.18_experimental-snapshot-1+build.2:v2"
modImplementation "net.fabricmc:fabric-loader:0.11.6"
}
'''
when: when:
def result = create("build", gradle) def result = gradle.run(task: "build")
then: then:
result.task(":build").outcome == SUCCESS result.task(":build").outcome == SUCCESS
where: where:
gradle | _ version << STANDARD_TEST_VERSIONS
DEFAULT_GRADLE | _
PRE_RELEASE_GRADLE | _
} }
} }

View File

@ -0,0 +1,69 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2021 FabricMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.fabricmc.loom.test.integration
import net.fabricmc.loom.test.util.GradleProjectTestTrait
import net.fabricmc.loom.test.util.ServerRunner
import spock.lang.Specification
import spock.lang.Timeout
import spock.lang.Unroll
import java.util.concurrent.TimeUnit
import static net.fabricmc.loom.test.LoomTestConstants.*
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
@Timeout(value = 30, unit = TimeUnit.MINUTES)
class FabricAPITest extends Specification implements GradleProjectTestTrait {
private static final String API_VERSION = "0.0.0+loom"
@Unroll
def "build and run (gradle #version)"() {
setup:
def gradle = gradleProject(
repo: "https://github.com/modmuss50/fabric.git",
commit: "cb31cccd34cb91f70cae6bac80208f5ec3650f33",
version: version
)
// Set the version to something constant
gradle.buildGradle.text = gradle.buildGradle.text.replace('Globals.baseVersion + "+" + (ENV.GITHUB_RUN_NUMBER ? "" : "local-") + getBranch()', "\"$API_VERSION\"")
def server = ServerRunner.create(gradle.projectDir, "1.17.1")
.withMod(gradle.getOutputFile("fabric-api-${API_VERSION}.jar"))
when:
def result = gradle.run(tasks: ["build", "publishToMavenLocal"], args: ["--parallel", "-x", "check"]) // Note: checkstyle does not appear to like being ran in a test runner
gradle.printOutputFiles()
def serverResult = server.run()
then:
result.task(":build").outcome == SUCCESS
serverResult.successful()
serverResult.output.contains("fabric@$API_VERSION")
where:
version << STANDARD_TEST_VERSIONS
}
}

View File

@ -24,27 +24,26 @@
package net.fabricmc.loom.test.integration package net.fabricmc.loom.test.integration
import net.fabricmc.loom.test.util.ProjectTestTrait import net.fabricmc.loom.test.util.GradleProjectTestTrait
import spock.lang.Specification import spock.lang.Specification
import spock.lang.Unroll import spock.lang.Unroll
import static net.fabricmc.loom.test.LoomTestConstants.*
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
class Java16ProjectTest extends Specification implements ProjectTestTrait { class Java16ProjectTest extends Specification implements GradleProjectTestTrait {
@Override
String name() {
"java16"
}
@Unroll @Unroll
def "build (gradle #gradle)"() { def "build (gradle #version)"() {
setup:
def gradle = gradleProject(project: "java16", version: version)
when: when:
def result = create("build", gradle) def result = gradle.run(task: "build")
then: then:
result.task(":build").outcome == SUCCESS result.task(":build").outcome == SUCCESS
where: where:
gradle | _ version << STANDARD_TEST_VERSIONS
DEFAULT_GRADLE | _
PRE_RELEASE_GRADLE | _
} }
} }

View File

@ -24,28 +24,26 @@
package net.fabricmc.loom.test.integration package net.fabricmc.loom.test.integration
import net.fabricmc.loom.test.util.ProjectTestTrait import net.fabricmc.loom.test.util.GradleProjectTestTrait
import spock.lang.IgnoreIf
import spock.lang.Specification import spock.lang.Specification
import spock.lang.Unroll import spock.lang.Unroll
import static net.fabricmc.loom.test.LoomTestConstants.*
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
class KotlinTest extends Specification implements ProjectTestTrait { class KotlinTest extends Specification implements GradleProjectTestTrait {
@Override
String name() {
"kotlin"
}
@Unroll @Unroll
def "kotlin build (gradle #gradle)"() { def "kotlin build (gradle #version)"() {
setup:
def gradle = gradleProject(project: "kotlin", version: version)
when: when:
def result = create("build", gradle) def result = gradle.run(task: "build")
then: then:
result.task(":build").outcome == SUCCESS result.task(":build").outcome == SUCCESS
where: where:
gradle | _ version << STANDARD_TEST_VERSIONS
DEFAULT_GRADLE | _
PRE_RELEASE_GRADLE | _
} }
} }

View File

@ -24,24 +24,27 @@
package net.fabricmc.loom.test.integration package net.fabricmc.loom.test.integration
import net.fabricmc.loom.test.util.ProjectTestTrait import net.fabricmc.loom.test.util.GradleProjectTestTrait
import spock.lang.Specification import spock.lang.Specification
import spock.lang.Unroll import spock.lang.Unroll
import static net.fabricmc.loom.test.LoomTestConstants.*
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
// This test uses gradle 4.9 and 1.14.4 v1 mappings // This test uses gradle 4.9 and 1.14.4 v1 mappings
class LegacyProjectTest extends Specification implements ProjectTestTrait { class LegacyProjectTest extends Specification implements GradleProjectTestTrait {
@Override
String name() {
"legacy"
}
@Unroll @Unroll
def "build"() { def "legacy build (gradle #version)"() {
setup:
def gradle = gradleProject(project: "legacy", version: version)
when: when:
def result = create("build", DEFAULT_GRADLE) def result = gradle.run(task: "build")
then: then:
result.task(":build").outcome == SUCCESS result.task(":build").outcome == SUCCESS
where:
version << STANDARD_TEST_VERSIONS
} }
} }

View File

@ -24,27 +24,26 @@
package net.fabricmc.loom.test.integration package net.fabricmc.loom.test.integration
import net.fabricmc.loom.test.util.ProjectTestTrait import net.fabricmc.loom.test.util.GradleProjectTestTrait
import spock.lang.Specification import spock.lang.Specification
import spock.lang.Unroll import spock.lang.Unroll
import static net.fabricmc.loom.test.LoomTestConstants.*
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
class LocalFileDependencyTest extends Specification implements ProjectTestTrait { class LocalFileDependencyTest extends Specification implements GradleProjectTestTrait {
@Override
String name() {
"localFileDependency"
}
@Unroll @Unroll
def "build (gradle #gradle)"() { def "build (gradle #version)"() {
setup:
def gradle = gradleProject(project: "localFileDependency", version: version)
when: when:
def result = create("build", gradle) def result = gradle.run(task: "build")
then: then:
result.task(":build").outcome == SUCCESS result.task(":build").outcome == SUCCESS
where: where:
gradle | _ version << STANDARD_TEST_VERSIONS
DEFAULT_GRADLE | _
PRE_RELEASE_GRADLE | _
} }
} }

View File

@ -24,13 +24,14 @@
package net.fabricmc.loom.test.integration package net.fabricmc.loom.test.integration
import net.fabricmc.loom.test.util.ArchiveAssertionsTrait import net.fabricmc.loom.test.util.GradleProjectTestTrait
import net.fabricmc.loom.test.util.MockMavenServerTrait import net.fabricmc.loom.test.util.MockMavenServerTrait
import spock.lang.Specification import spock.lang.Specification
import spock.lang.Stepwise import spock.lang.Stepwise
import spock.lang.Unroll import spock.lang.Unroll
import spock.util.environment.RestoreSystemProperties import spock.util.environment.RestoreSystemProperties
import static net.fabricmc.loom.test.LoomTestConstants.*
import static java.lang.System.setProperty import static java.lang.System.setProperty
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
@ -38,20 +39,23 @@ import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
* This tests publishing a range of versions and then tries to resolve and build against them * This tests publishing a range of versions and then tries to resolve and build against them
*/ */
@Stepwise @Stepwise
class MavenProjectTest extends Specification implements MockMavenServerTrait, ArchiveAssertionsTrait { class MavenProjectTest extends Specification implements MockMavenServerTrait, GradleProjectTestTrait {
@RestoreSystemProperties @RestoreSystemProperties
@Unroll @Unroll
def "publish lib #version #gradle"() { def "publish lib #version #gradleVersion"() {
given: setup:
setProperty('loom.test.version', version) setProperty('loom.test.version', version)
library = true def gradle = gradleProject(project: "mavenLibrary", version: gradleVersion, sharedFiles: true)
when: when:
def result = create("publish", gradle) def result = gradle.run(tasks: ["clean", "publish"])
then: then:
result.task(":publish").outcome == SUCCESS result.task(":publish").outcome == SUCCESS
hasArchiveEntry("fabric-example-lib-${version}.jar", "net/fabricmc/example/ExampleLib.class") gradle.hasOutputZipEntry("fabric-example-lib-${version}.jar", "net/fabricmc/example/ExampleLib.class")
where: where:
version | gradle version | gradleVersion
'1.0.0' | DEFAULT_GRADLE '1.0.0' | DEFAULT_GRADLE
'1.0.0' | PRE_RELEASE_GRADLE '1.0.0' | PRE_RELEASE_GRADLE
'1.1.0' | DEFAULT_GRADLE '1.1.0' | DEFAULT_GRADLE
@ -64,17 +68,20 @@ class MavenProjectTest extends Specification implements MockMavenServerTrait, Ar
@RestoreSystemProperties @RestoreSystemProperties
@Unroll @Unroll
def "resolve #version #gradle"() { def "resolve #version #gradleVersion"() {
given: given:
setProperty('loom.test.resolve', "com.example:fabric-example-lib:${version}") setProperty('loom.test.resolve', "com.example:fabric-example-lib:${version}")
library = false def gradle = gradleProject(project: "maven", version: gradleVersion, sharedFiles: true)
when: when:
def result = create("build", gradle) def result = gradle.run(tasks: ["clean", "build"])
then: then:
result.task(":build").outcome == SUCCESS result.task(":build").outcome == SUCCESS
hasArchiveEntry("fabric-example-mod-1.0.0.jar", "net/fabricmc/examplemod/ExampleMod.class") gradle.hasOutputZipEntry("fabric-example-mod-1.0.0.jar", "net/fabricmc/examplemod/ExampleMod.class")
where: where:
version | gradle version | gradleVersion
'1.0.0' | DEFAULT_GRADLE '1.0.0' | DEFAULT_GRADLE
'1.0.0' | PRE_RELEASE_GRADLE '1.0.0' | PRE_RELEASE_GRADLE
'1.1.+' | DEFAULT_GRADLE '1.1.+' | DEFAULT_GRADLE
@ -87,12 +94,4 @@ class MavenProjectTest extends Specification implements MockMavenServerTrait, Ar
'2.0.0-SNAPSHOT:classifier' | DEFAULT_GRADLE '2.0.0-SNAPSHOT:classifier' | DEFAULT_GRADLE
'master-SNAPSHOT:classifier' | DEFAULT_GRADLE 'master-SNAPSHOT:classifier' | DEFAULT_GRADLE
} }
// Set to true when to build and publish the mavenLibrary
private boolean library = false
@Override
String name() {
library ? "mavenLibrary" : "maven"
}
} }

View File

@ -24,53 +24,50 @@
package net.fabricmc.loom.test.integration package net.fabricmc.loom.test.integration
import net.fabricmc.loom.test.util.ProjectTestTrait import net.fabricmc.loom.test.util.GradleProjectTestTrait
import spock.lang.Specification import spock.lang.Specification
import spock.lang.Unroll import spock.lang.Unroll
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import java.util.jar.JarFile import java.util.jar.JarFile
import static net.fabricmc.loom.test.LoomTestConstants.STANDARD_TEST_VERSIONS
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
class MixinApAutoRefmapTest extends Specification implements ProjectTestTrait { class MixinApAutoRefmapTest extends Specification implements GradleProjectTestTrait {
@Override
String name() {
"mixinApAutoRefmap"
}
@Unroll @Unroll
def "build (gradle #gradle)"() { def "build (gradle #version)"() {
setup:
def gradle = gradleProject(project: "mixinApAutoRefmap", version: version)
when: when:
def result = create("build", gradle) def result = gradle.run(task: "build")
then: then:
result.task(":build").outcome == SUCCESS result.task(":build").outcome == SUCCESS
// verify the ref-map name is correctly generated // verify the ref-map name is correctly generated
def jar = new JarFile(getOutputFile("fabric-example-mod-1.0.0-universal.jar").absoluteFile) def jar = new JarFile(gradle.getOutputFile("fabric-example-mod-1.0.0-universal.jar").absoluteFile)
jar.getEntry("refmap0000.json") == null jar.getEntry("refmap0000.json") == null
jar.getEntry("refmap0001.json") != null jar.getEntry("refmap0001.json") != null
jar.getEntry("refmap0002.json") != null jar.getEntry("refmap0002.json") != null
jar.getEntry("refmap0003.json") != null jar.getEntry("refmap0003.json") != null
def j1 = JsonParser.parseReader(new InputStreamReader(jar.getInputStream(jar.getEntry("main.mixins.json")))) def j1 = JsonParser.parseReader(new InputStreamReader(jar.getInputStream(jar.getEntry("main.mixins.json"))))
j1.asJsonObject.getAsJsonPrimitive("refmap").getAsString() == "refmap0001.json" j1.asJsonObject.getAsJsonPrimitive("refmap").getAsString() == "refmap0001.json"
def j2 = JsonParser.parseReader(new InputStreamReader(jar.getInputStream(jar.getEntry("blabla.json")))) def j2 = JsonParser.parseReader(new InputStreamReader(jar.getInputStream(jar.getEntry("blabla.json"))))
j2.asJsonObject.getAsJsonPrimitive("refmap").getAsString() == "refmap0002.json" j2.asJsonObject.getAsJsonPrimitive("refmap").getAsString() == "refmap0002.json"
def j3 = JsonParser.parseReader(new InputStreamReader(jar.getInputStream(jar.getEntry("m1_1.mixins.json")))) def j3 = JsonParser.parseReader(new InputStreamReader(jar.getInputStream(jar.getEntry("m1_1.mixins.json"))))
j3.asJsonObject.getAsJsonPrimitive("refmap").getAsString() == "refmap0003.json" j3.asJsonObject.getAsJsonPrimitive("refmap").getAsString() == "refmap0003.json"
def j4 = JsonParser.parseReader(new InputStreamReader(jar.getInputStream(jar.getEntry("m1_2.mixins.json")))) def j4 = JsonParser.parseReader(new InputStreamReader(jar.getInputStream(jar.getEntry("m1_2.mixins.json"))))
!j4.asJsonObject.has("refmap") !j4.asJsonObject.has("refmap")
def j5 = JsonParser.parseReader(new InputStreamReader(jar.getInputStream(jar.getEntry("irrelevant.mixins.json")))) def j5 = JsonParser.parseReader(new InputStreamReader(jar.getInputStream(jar.getEntry("irrelevant.mixins.json"))))
!j5.asJsonObject.has("refmap") !j5.asJsonObject.has("refmap")
where: where:
gradle | _ version << STANDARD_TEST_VERSIONS
DEFAULT_GRADLE | _
PRE_RELEASE_GRADLE | _
} }
} }

View File

@ -24,40 +24,38 @@
package net.fabricmc.loom.test.integration package net.fabricmc.loom.test.integration
import net.fabricmc.loom.test.util.ProjectTestTrait import net.fabricmc.loom.test.util.GradleProjectTestTrait
import spock.lang.Specification import spock.lang.Specification
import spock.lang.Unroll import spock.lang.Unroll
import java.util.jar.JarFile import java.util.jar.JarFile
import static net.fabricmc.loom.test.LoomTestConstants.*
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
class MixinApSimpleTest extends Specification implements ProjectTestTrait { class MixinApSimpleTest extends Specification implements GradleProjectTestTrait {
@Override
String name() {
"mixinApSimple"
}
@Unroll @Unroll
def "build (gradle #gradle)"() { def "build (gradle #version)"() {
setup:
def gradle = gradleProject(project: "mixinApSimple", version: version)
when: when:
def result = create("build", gradle) def result = gradle.run(task: "build")
then: then:
result.task(":build").outcome == SUCCESS result.task(":build").outcome == SUCCESS
// verify the ref-map name is correctly generated // verify the ref-map name is correctly generated
def main = new JarFile(getOutputFile("fabric-example-mod-1.0.0-dev.jar").absoluteFile) def main = new JarFile(gradle.getOutputFile("fabric-example-mod-1.0.0-dev.jar").absoluteFile)
main.getEntry("main-refmap0000.json") != null main.getEntry("main-refmap0000.json") != null
def mixin = new JarFile(getOutputFile("fabric-example-mod-1.0.0-mixin.jar").absoluteFile) def mixin = new JarFile(gradle.getOutputFile("fabric-example-mod-1.0.0-mixin.jar").absoluteFile)
mixin.getEntry("default-refmap0000.json") != null mixin.getEntry("default-refmap0000.json") != null
def mixin1 = new JarFile(getOutputFile("fabric-example-mod-1.0.0-mixin1.jar").absoluteFile) def mixin1 = new JarFile(gradle.getOutputFile("fabric-example-mod-1.0.0-mixin1.jar").absoluteFile)
mixin1.getEntry("main-refmap0000.json") == null mixin1.getEntry("main-refmap0000.json") == null
mixin1.getEntry("default-refmap0000.json") == null mixin1.getEntry("default-refmap0000.json") == null
where: where:
gradle | _ version << STANDARD_TEST_VERSIONS
DEFAULT_GRADLE | _
PRE_RELEASE_GRADLE | _
} }
} }

View File

@ -24,27 +24,26 @@
package net.fabricmc.loom.test.integration package net.fabricmc.loom.test.integration
import net.fabricmc.loom.test.util.ProjectTestTrait import net.fabricmc.loom.test.util.GradleProjectTestTrait
import spock.lang.Specification import spock.lang.Specification
import spock.lang.Unroll import spock.lang.Unroll
import static net.fabricmc.loom.test.LoomTestConstants.*
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
class MojangMappingsProjectTest extends Specification implements ProjectTestTrait { class MojangMappingsProjectTest extends Specification implements GradleProjectTestTrait {
@Override
String name() {
"mojangMappings"
}
@Unroll @Unroll
def "build (gradle #gradle)"() { def "build (gradle #version)"() {
setup:
def gradle = gradleProject(project: "mojangMappings", version: version)
when: when:
def result = create("build", gradle) def result = gradle.run(task: "build")
then: then:
result.task(":build").outcome == SUCCESS result.task(":build").outcome == SUCCESS
where: where:
gradle | _ version << STANDARD_TEST_VERSIONS
DEFAULT_GRADLE | _
PRE_RELEASE_GRADLE | _
} }
} }

View File

@ -24,23 +24,22 @@
package net.fabricmc.loom.test.integration package net.fabricmc.loom.test.integration
import net.fabricmc.loom.test.util.ArchiveAssertionsTrait import net.fabricmc.loom.test.util.GradleProjectTestTrait
import net.fabricmc.loom.test.util.ProjectTestTrait
import spock.lang.Specification import spock.lang.Specification
import spock.lang.Unroll import spock.lang.Unroll
import static net.fabricmc.loom.test.LoomTestConstants.STANDARD_TEST_VERSIONS
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
class MultiProjectTest extends Specification implements ProjectTestTrait, ArchiveAssertionsTrait { class MultiProjectTest extends Specification implements GradleProjectTestTrait {
@Override
String name() {
"multiproject"
}
@Unroll @Unroll
def "build (gradle #gradle)"() { def "build (gradle #version)"() {
setup:
def gradle = gradleProject(project: "multiproject", version: version)
when: when:
def result = create("build", gradle) def result = gradle.run(task: "build")
then: then:
result.task(":build").outcome == SUCCESS result.task(":build").outcome == SUCCESS
result.task(":core:build").outcome == SUCCESS result.task(":core:build").outcome == SUCCESS
@ -49,13 +48,11 @@ class MultiProjectTest extends Specification implements ProjectTestTrait, Archiv
result.task(":remapAllJars").outcome == SUCCESS result.task(":remapAllJars").outcome == SUCCESS
result.task(":remapAllSources").outcome == SUCCESS result.task(":remapAllSources").outcome == SUCCESS
hasArchiveEntry("multiproject-1.0.0.jar", "META-INF/jars/example-1.0.0.jar") gradle.hasOutputZipEntry("multiproject-1.0.0.jar", "META-INF/jars/example-1.0.0.jar")
hasArchiveEntry("multiproject-1.0.0.jar", "META-INF/jars/core-1.0.0.jar") gradle.hasOutputZipEntry("multiproject-1.0.0.jar", "META-INF/jars/core-1.0.0.jar")
hasArchiveEntry("multiproject-1.0.0.jar", "META-INF/jars/fabric-api-base-0.2.1+9354966b7d.jar") gradle.hasOutputZipEntry("multiproject-1.0.0.jar", "META-INF/jars/fabric-api-base-0.2.1+9354966b7d.jar")
where: where:
gradle | _ version << STANDARD_TEST_VERSIONS
DEFAULT_GRADLE | _
PRE_RELEASE_GRADLE | _
} }
} }

View File

@ -24,29 +24,26 @@
package net.fabricmc.loom.test.integration package net.fabricmc.loom.test.integration
import net.fabricmc.loom.test.util.ProjectTestTrait import net.fabricmc.loom.test.util.GradleProjectTestTrait
import spock.lang.Specification import spock.lang.Specification
import spock.lang.Unroll import spock.lang.Unroll
import static net.fabricmc.loom.test.LoomTestConstants.STANDARD_TEST_VERSIONS
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
class ParchmentTest extends Specification implements ProjectTestTrait { class ParchmentTest extends Specification implements GradleProjectTestTrait {
@Override
String name() {
"parchment"
}
@Unroll @Unroll
def "parchment #gradle"() { def "parchment #version"() {
setup:
def gradle = gradleProject(project: "parchment", version: version)
when: when:
def result = create("build", gradle) def result = gradle.run(task: "build")
then: then:
result.task(":build").outcome == SUCCESS result.task(":build").outcome == SUCCESS
where: where:
gradle | _ version << STANDARD_TEST_VERSIONS
DEFAULT_GRADLE | _
PRE_RELEASE_GRADLE | _
} }
} }

View File

@ -27,40 +27,37 @@ package net.fabricmc.loom.test.integration
import com.google.common.hash.HashCode import com.google.common.hash.HashCode
import com.google.common.hash.Hashing import com.google.common.hash.Hashing
import com.google.common.io.Files import com.google.common.io.Files
import net.fabricmc.loom.test.util.ProjectTestTrait import net.fabricmc.loom.test.util.GradleProjectTestTrait
import spock.lang.Specification import spock.lang.Specification
import spock.lang.Unroll import spock.lang.Unroll
import spock.util.environment.RestoreSystemProperties import spock.util.environment.RestoreSystemProperties
import static net.fabricmc.loom.test.LoomTestConstants.*
import static java.lang.System.setProperty import static java.lang.System.setProperty
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
class ReproducibleBuildTest extends Specification implements ProjectTestTrait { class ReproducibleBuildTest extends Specification implements GradleProjectTestTrait {
@Override
String name() {
"reproducible"
}
@RestoreSystemProperties @RestoreSystemProperties
@Unroll @Unroll
def "build (gradle #gradle)"() { def "build (gradle #version)"() {
setup:
def gradle = gradleProject(project: "reproducible", version: version)
when: when:
setProperty('loom.test.reproducible', 'true') setProperty('loom.test.reproducible', 'true')
def result = create("build", gradle) def result = gradle.run(task: "build")
then: then:
result.task(":build").outcome == SUCCESS result.task(":build").outcome == SUCCESS
getOutputHash("fabric-example-mod-1.0.0.jar") == modHash generateMD5(gradle.getOutputFile("fabric-example-mod-1.0.0.jar")) == modHash
getOutputHash("fabric-example-mod-1.0.0-sources.jar") in sourceHash // Done for different line endings. generateMD5(gradle.getOutputFile("fabric-example-mod-1.0.0-sources.jar")) in sourceHash // Done for different line endings.
where: where:
gradle | modHash | sourceHash version | modHash | sourceHash
DEFAULT_GRADLE | "ed3306ef60f434c55048cba8de5dab95" | ["be31766e6cafbe4ae3bca9e35ba63169", "7348b0bd87d36d7ec6f3bca9c2b66062"] DEFAULT_GRADLE | "ed3306ef60f434c55048cba8de5dab95" | ["be31766e6cafbe4ae3bca9e35ba63169", "7348b0bd87d36d7ec6f3bca9c2b66062"]
PRE_RELEASE_GRADLE | "ed3306ef60f434c55048cba8de5dab95" | ["be31766e6cafbe4ae3bca9e35ba63169", "7348b0bd87d36d7ec6f3bca9c2b66062"] PRE_RELEASE_GRADLE | "ed3306ef60f434c55048cba8de5dab95" | ["be31766e6cafbe4ae3bca9e35ba63169", "7348b0bd87d36d7ec6f3bca9c2b66062"]
} }
String getOutputHash(String name) {
generateMD5(getOutputFile(name))
}
String generateMD5(File file) { String generateMD5(File file) {
HashCode hash = Files.asByteSource(file).hash(Hashing.md5()) HashCode hash = Files.asByteSource(file).hash(Hashing.md5())
return hash.asBytes().encodeHex() as String return hash.asBytes().encodeHex() as String

View File

@ -24,25 +24,25 @@
package net.fabricmc.loom.test.integration package net.fabricmc.loom.test.integration
import net.fabricmc.loom.test.util.ProjectTestTrait import net.fabricmc.loom.test.util.GradleProjectTestTrait
import spock.lang.Specification import spock.lang.Specification
import spock.lang.Unroll import spock.lang.Unroll
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
// This test runs a mod that exits on mod init // This test runs a mod that exits on mod init
class RunConfigTest extends Specification implements ProjectTestTrait { class RunConfigTest extends Specification implements GradleProjectTestTrait {
@Override
String name() {
"runconfigs"
}
@Unroll @Unroll
def "#task"() { def "Run config #task"() {
setup:
def gradle = gradleProject(project: "runconfigs", sharedFiles: true)
when: when:
def result = create(task) def result = gradle.run(task: task)
then: then:
result.task(":${task}").outcome == SUCCESS result.task(":${task}").outcome == SUCCESS
where: where:
task | _ task | _
'runClient' | _ 'runClient' | _

View File

@ -24,14 +24,14 @@
package net.fabricmc.loom.test.integration package net.fabricmc.loom.test.integration
import net.fabricmc.loom.test.util.ArchiveAssertionsTrait import net.fabricmc.loom.test.util.GradleProjectTestTrait
import net.fabricmc.loom.test.util.MockMavenServerTrait import net.fabricmc.loom.test.util.MockMavenServerTrait
import spock.lang.Specification import spock.lang.Specification
import spock.lang.Stepwise import spock.lang.Stepwise
import spock.lang.Unroll import spock.lang.Unroll
import spock.util.environment.RestoreSystemProperties import spock.util.environment.RestoreSystemProperties
import static net.fabricmc.loom.test.LoomTestConstants.*
import static java.lang.System.setProperty import static java.lang.System.setProperty
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
@ -39,25 +39,22 @@ import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
* This tests publishing signed artifacts to a maven server * This tests publishing signed artifacts to a maven server
*/ */
@Stepwise @Stepwise
class SignedProjectTest extends Specification implements MockMavenServerTrait, ArchiveAssertionsTrait { class SignedProjectTest extends Specification implements MockMavenServerTrait, GradleProjectTestTrait {
@Unroll @Unroll
@RestoreSystemProperties @RestoreSystemProperties
def "sign and publish lib #gradle"() { def "sign and publish lib #version"() {
given: setup:
setProperty('loom.test.secretKey', PRIVATE_KEY) setProperty('loom.test.secretKey', PRIVATE_KEY)
def gradle = gradleProject(project: "signed", version: version)
when: when:
def result = create("publish", gradle) def result = gradle.run(task: "publish")
then: then:
result.task(":publish").outcome == SUCCESS result.task(":publish").outcome == SUCCESS
where:
gradle | _
DEFAULT_GRADLE | _
PRE_RELEASE_GRADLE | _
}
@Override where:
String name() { version << STANDARD_TEST_VERSIONS
"signed"
} }
static final String PRIVATE_KEY = """ static final String PRIVATE_KEY = """

View File

@ -24,36 +24,48 @@
package net.fabricmc.loom.test.integration package net.fabricmc.loom.test.integration
import net.fabricmc.loom.test.util.ArchiveAssertionsTrait import net.fabricmc.loom.test.util.GradleProjectTestTrait
import net.fabricmc.loom.test.util.ProjectTestTrait import net.fabricmc.loom.test.util.ServerRunner
import spock.lang.Specification import spock.lang.Specification
import spock.lang.Timeout
import spock.lang.Unroll import spock.lang.Unroll
import java.util.concurrent.TimeUnit
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
import static net.fabricmc.loom.test.LoomTestConstants.*
class SimpleProjectTest extends Specification implements ProjectTestTrait, ArchiveAssertionsTrait { @Timeout(value = 20, unit = TimeUnit.MINUTES)
@Override class SimpleProjectTest extends Specification implements GradleProjectTestTrait {
String name() {
"simple"
}
@Unroll @Unroll
def "build (gradle #gradle)"() { def "build and run (gradle #version)"() {
setup:
def gradle = gradleProject(project: "simple", version: version)
def server = ServerRunner.create(gradle.projectDir, "1.16.5")
.withMod(gradle.getOutputFile("fabric-example-mod-1.0.0.jar"))
.withFabricApi()
when: when:
def result = create("build", gradle) def result = gradle.run(task: "build")
def serverResult = server.run()
then: then:
result.task(":build").outcome == SUCCESS result.task(":build").outcome == SUCCESS
getArchiveEntry("fabric-example-mod-1.0.0.jar", "META-INF/MANIFEST.MF").contains("Fabric-Loom-Version: 0.0.0+unknown") gradle.getOutputZipEntry("fabric-example-mod-1.0.0.jar", "META-INF/MANIFEST.MF").contains("Fabric-Loom-Version: 0.0.0+unknown")
serverResult.successful()
serverResult.output.contains("Hello simple Fabric mod") // A check to ensure our mod init was actually called
where: where:
gradle | _ version | _
DEFAULT_GRADLE | _ DEFAULT_GRADLE | _
PRE_RELEASE_GRADLE | _ PRE_RELEASE_GRADLE | _
} }
@Unroll @Unroll
def "#ide config generation"() { def "#ide config generation"() {
setup:
def gradle = gradleProject(project: "simple", sharedFiles: true)
when: when:
def result = create(ide) def result = gradle.run(task: ide)
then: then:
result.task(":${ide}").outcome == SUCCESS result.task(":${ide}").outcome == SUCCESS
where: where:

View File

@ -24,47 +24,48 @@
package net.fabricmc.loom.test.integration package net.fabricmc.loom.test.integration
import net.fabricmc.loom.test.util.ProjectTestTrait import net.fabricmc.loom.test.util.GradleProjectTestTrait
import org.zeroturnaround.zip.ZipUtil import org.zeroturnaround.zip.ZipUtil
import spock.lang.Specification import spock.lang.Specification
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
import static net.fabricmc.loom.test.LoomTestConstants.*
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
class UnpickTest extends Specification implements ProjectTestTrait { class UnpickTest extends Specification implements GradleProjectTestTrait {
static final String MAPPINGS = "21w13a/net.fabricmc.yarn.21w13a.21w13a+build.30-v2" static final String MAPPINGS = "21w13a/net.fabricmc.yarn.21w13a.21w13a+build.30-v2"
@Override
String name() {
"unpick"
}
def "unpick decompile"() { def "unpick decompile"() {
setup:
def gradle = gradleProject(project: "unpick", version: version)
when: when:
def result = create("genSources", gradle) def result = gradle.run(task: "genSources")
then: then:
result.task(":genSources").outcome == SUCCESS result.task(":genSources").outcome == SUCCESS
getClassSource("net/minecraft/block/CakeBlock.java").contains("Block.DEFAULT_SET_BLOCK_STATE_FLAG") getClassSource(gradle, "net/minecraft/block/CakeBlock.java").contains("Block.DEFAULT_SET_BLOCK_STATE_FLAG")
where: where:
gradle | _ version << STANDARD_TEST_VERSIONS
DEFAULT_GRADLE | _
PRE_RELEASE_GRADLE | _
} }
def "unpick build"() { def "unpick build"() {
setup:
def gradle = gradleProject(project: "unpick", version: version)
when: when:
def result = create("build", gradle) def result = gradle.run(task: "build")
then: then:
result.task(":build").outcome == SUCCESS result.task(":build").outcome == SUCCESS
where: where:
gradle | _ version << STANDARD_TEST_VERSIONS
DEFAULT_GRADLE | _
PRE_RELEASE_GRADLE | _
} }
String getClassSource(String classname, String mappings = MAPPINGS) { private static String getClassSource(GradleProject gradle, String classname, String mappings = MAPPINGS) {
File sourcesJar = getGeneratedSources(mappings) File sourcesJar = gradle.getGeneratedSources(mappings)
return new String(ZipUtil.unpackEntry(sourcesJar, classname), StandardCharsets.UTF_8) return new String(ZipUtil.unpackEntry(sourcesJar, classname), StandardCharsets.UTF_8)
} }
} }

View File

@ -33,7 +33,6 @@ import net.fabricmc.loom.configuration.providers.mappings.MappingLayer
import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider
import net.fabricmc.loom.configuration.providers.mappings.MappingsSpec import net.fabricmc.loom.configuration.providers.mappings.MappingsSpec
import net.fabricmc.mappingio.format.Tiny2Writer import net.fabricmc.mappingio.format.Tiny2Writer
import net.fabricmc.mappingio.tree.MappingTree
import net.fabricmc.mappingio.tree.MemoryMappingTree import net.fabricmc.mappingio.tree.MemoryMappingTree
import org.gradle.api.logging.Logger import org.gradle.api.logging.Logger
import spock.lang.Specification import spock.lang.Specification

View File

@ -31,14 +31,14 @@ interface LayeredMappingsTestConstants {
public static final String INTERMEDIARY_1_16_5_URL = "https://maven.fabricmc.net/net/fabricmc/intermediary/1.16.5/intermediary-1.16.5-v2.jar" public static final String INTERMEDIARY_1_16_5_URL = "https://maven.fabricmc.net/net/fabricmc/intermediary/1.16.5/intermediary-1.16.5-v2.jar"
public static final Map<String, MinecraftVersionMeta.Download> DOWNLOADS_1_17 = [ public static final Map<String, MinecraftVersionMeta.Download> DOWNLOADS_1_17 = [
client_mappings:new MinecraftVersionMeta.Download(null, "227d16f520848747a59bef6f490ae19dc290a804", 6431705, "https://launcher.mojang.com/v1/objects/227d16f520848747a59bef6f490ae19dc290a804/client.txt"), client_mappings: new MinecraftVersionMeta.Download(null, "227d16f520848747a59bef6f490ae19dc290a804", 6431705, "https://launcher.mojang.com/v1/objects/227d16f520848747a59bef6f490ae19dc290a804/client.txt"),
server_mappings:new MinecraftVersionMeta.Download(null, "84d80036e14bc5c7894a4fad9dd9f367d3000334", 4948536, "https://launcher.mojang.com/v1/objects/84d80036e14bc5c7894a4fad9dd9f367d3000334/server.txt") server_mappings: new MinecraftVersionMeta.Download(null, "84d80036e14bc5c7894a4fad9dd9f367d3000334", 4948536, "https://launcher.mojang.com/v1/objects/84d80036e14bc5c7894a4fad9dd9f367d3000334/server.txt")
] ]
public static final MinecraftVersionMeta VERSION_META_1_17 = new MinecraftVersionMeta(null, null, null, 0, DOWNLOADS_1_17, null, null, null, null, 0, null, null, null) public static final MinecraftVersionMeta VERSION_META_1_17 = new MinecraftVersionMeta(null, null, null, 0, DOWNLOADS_1_17, null, null, null, null, 0, null, null, null)
public static final Map<String, MinecraftVersionMeta.Download> DOWNLOADS_1_16_5 = [ public static final Map<String, MinecraftVersionMeta.Download> DOWNLOADS_1_16_5 = [
client_mappings:new MinecraftVersionMeta.Download(null, "e3dfb0001e1079a1af72ee21517330edf52e6192", 5746047, "https://launcher.mojang.com/v1/objects/e3dfb0001e1079a1af72ee21517330edf52e6192/client.txt"), client_mappings: new MinecraftVersionMeta.Download(null, "e3dfb0001e1079a1af72ee21517330edf52e6192", 5746047, "https://launcher.mojang.com/v1/objects/e3dfb0001e1079a1af72ee21517330edf52e6192/client.txt"),
server_mappings:new MinecraftVersionMeta.Download(null, "81d5c793695d8cde63afddb40dde88e3a88132ac", 4400926, "https://launcher.mojang.com/v1/objects/81d5c793695d8cde63afddb40dde88e3a88132ac/server.txt") server_mappings: new MinecraftVersionMeta.Download(null, "81d5c793695d8cde63afddb40dde88e3a88132ac", 4400926, "https://launcher.mojang.com/v1/objects/81d5c793695d8cde63afddb40dde88e3a88132ac/server.txt")
] ]
public static final MinecraftVersionMeta VERSION_META_1_16_5 = new MinecraftVersionMeta(null, null, null, 0, DOWNLOADS_1_16_5, null, null, null, null, 0, null, null, null) public static final MinecraftVersionMeta VERSION_META_1_16_5 = new MinecraftVersionMeta(null, null, null, 0, DOWNLOADS_1_16_5, null, null, null, null, 0, null, null, null)

View File

@ -27,7 +27,6 @@ package net.fabricmc.loom.test.unit.layeredmappings
import net.fabricmc.loom.configuration.providers.mappings.intermediary.IntermediaryMappingsSpec import net.fabricmc.loom.configuration.providers.mappings.intermediary.IntermediaryMappingsSpec
import net.fabricmc.loom.configuration.providers.mappings.mojmap.MojangMappingsSpec import net.fabricmc.loom.configuration.providers.mappings.mojmap.MojangMappingsSpec
import net.fabricmc.loom.configuration.providers.mappings.parchment.ParchmentMappingsSpec import net.fabricmc.loom.configuration.providers.mappings.parchment.ParchmentMappingsSpec
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta
class ParchmentMappingLayerTest extends LayeredMappingsSpecification { class ParchmentMappingLayerTest extends LayeredMappingsSpecification {
def "Read parchment mappings" () { def "Read parchment mappings" () {

View File

@ -0,0 +1,203 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2021 FabricMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.fabricmc.loom.test.util
import groovy.transform.Immutable
import net.fabricmc.loom.test.LoomTestConstants
import org.gradle.testkit.runner.BuildResult
import org.gradle.testkit.runner.GradleRunner
import org.zeroturnaround.zip.ZipUtil
import spock.lang.Shared
trait GradleProjectTestTrait {
@Lazy
@Shared
private static File sharedProjectDir = File.createTempDir()
@Lazy
@Shared
private static File sharedGradleHomeDir = File.createTempDir()
GradleProject gradleProject(Map options) {
String gradleVersion = options.version as String ?: LoomTestConstants.DEFAULT_GRADLE
String warningMode = options.warningMode as String ?: "fail"
File projectDir = options.projectDir as File ?: options.sharedFiles ? sharedProjectDir : File.createTempDir()
File gradleHomeDir = options.gradleHomeDir as File ?: options.sharedFiles ? sharedGradleHomeDir : File.createTempDir()
setupProject(options, projectDir)
return new GradleProject(
gradleVersion: gradleVersion,
projectDir: projectDir.absolutePath,
gradleHomeDir: gradleHomeDir.absolutePath,
warningMode: warningMode
)
}
private void setupProject(Map options, File projectDir) {
if (options.project) {
copyProjectFromResources(options.project as String, projectDir)
return
}
if (options["repo"]) {
String repo = options.repo
String commit = options.commit
exec(projectDir, "git", "clone", repo, ".")
exec(projectDir, "git", "checkout", commit)
return
}
throw new UnsupportedOperationException("No project setup method was supplied")
}
private void exec(File projectDir, String... args) {
def process = args.execute([], projectDir)
process.consumeProcessOutput(System.out, System.err)
def exitCode = process.waitFor()
if (exitCode != 0) {
throw new RuntimeException("Command failed with exit code: $exitCode")
}
}
private void copyProjectFromResources(String project, File projectDir) {
def projectSourceDir = new File("src/test/resources/projects/$project")
if (!projectSourceDir.exists()) {
throw new FileNotFoundException("Failed to find project directory at: $projectSourceDir.absolutePath")
}
// Cleanup some basic things if they already exists
new File(projectDir, "src").deleteDir()
new File(projectDir, "build.gradle").delete()
new File(projectDir, "settings.gradle").delete()
projectSourceDir.eachFileRecurse { file ->
if (file.isDirectory()) {
return
}
def path = file.path.replace(projectSourceDir.path, "")
File tempFile = new File(projectDir, path)
if (tempFile.exists()) {
tempFile.delete()
}
tempFile.parentFile.mkdirs()
tempFile.bytes = file.bytes
}
}
@Immutable
static class GradleProject {
private String gradleVersion
private String projectDir
private String gradleHomeDir
private String warningMode
BuildResult run(Map options) {
// Setup the system props to tell loom that its running in a test env
// And override the CI check to ensure that everything is ran
System.setProperty("fabric.loom.test", "true")
System.setProperty("fabric.loom.ci", "false")
System.setProperty("maven.repo.local", new File(getGradleHomeDir(), "m2").absolutePath)
def runner = this.runner
def args = []
if (options.task) {
args << options.task
}
args.addAll(options.tasks ?: [])
args << "--stacktrace"
args << "--warning-mode" << warningMode
args << "--gradle-user-home" << gradleHomeDir
args.addAll(options.args ?: [])
runner.withArguments(args as String[])
return runner.build()
}
private GradleRunner getRunner() {
return GradleRunner.create()
.withProjectDir(getProjectDir())
.withPluginClasspath()
.withGradleVersion(gradleVersion)
.forwardOutput()
.withDebug(true)
}
File getProjectDir() {
return new File(projectDir)
}
File getGradleHomeDir() {
return new File(gradleHomeDir)
}
File getOutputFile(String filename) {
return new File(getProjectDir(), "build/libs/$filename")
}
void printOutputFiles() {
new File(getProjectDir(), "build/libs/").listFiles().each {
println(it.name)
}
}
File getBuildGradle() {
return new File(getProjectDir(), "build.gradle")
}
String getOutputZipEntry(String filename, String entryName) {
def file = getOutputFile(filename)
def bytes = ZipUtil.unpackEntry(file, entryName)
if (bytes == null) {
throw new FileNotFoundException("Could not find ${entryName} in ${entryName}")
}
new String(bytes as byte[])
}
boolean hasOutputZipEntry(String filename, String entryName) {
def file = getOutputFile(filename)
return ZipUtil.unpackEntry(file, entryName) != null
}
File getGeneratedSources(String mappings) {
return new File(getGradleHomeDir(), "caches/fabric-loom/${mappings}/minecraft-mapped-sources.jar")
}
}
}

View File

@ -27,7 +27,7 @@ package net.fabricmc.loom.test.util
import io.javalin.Javalin import io.javalin.Javalin
import org.apache.commons.io.IOUtils import org.apache.commons.io.IOUtils
trait MockMavenServerTrait extends ProjectTestTrait { trait MockMavenServerTrait {
public final int mavenServerPort = 9876 public final int mavenServerPort = 9876
public final File testMavenDir = File.createTempDir() public final File testMavenDir = File.createTempDir()
private Javalin server private Javalin server
@ -74,7 +74,6 @@ trait MockMavenServerTrait extends ProjectTestTrait {
@SuppressWarnings('unused') @SuppressWarnings('unused')
def cleanupSpec() { def cleanupSpec() {
server.stop() server.stop()
super.cleanupSpec()
} }
File getMavenDirectory() { File getMavenDirectory() {

View File

@ -1,126 +0,0 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2016-2021 FabricMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.fabricmc.loom.test.util
import org.gradle.testkit.runner.BuildResult
import org.gradle.testkit.runner.GradleRunner
trait ProjectTestTrait {
final static String DEFAULT_GRADLE = "7.0.1"
final static String PRE_RELEASE_GRADLE = "7.3-20210724022245+0000"
static File gradleHome = File.createTempDir()
File testProjectDir = File.createTempDir()
abstract String name()
def copyInputFiles() {
println "Project directory: ${testProjectDir}"
def baseProjectDir = new File("src/test/resources/projects/" + name())
if (!baseProjectDir.exists()) {
throw new FileNotFoundException("Failed to find project directory at:" + baseProjectDir.absolutePath)
}
baseProjectDir.eachFileRecurse { file ->
if (file.isDirectory()) {
return
}
def path = file.path.replace(baseProjectDir.path, "")
File tempFile = new File(testProjectDir, path)
if (tempFile.exists()) {
tempFile.delete()
}
tempFile.parentFile.mkdirs()
tempFile.bytes = file.bytes
}
// Disable the CI checks to ensure nothing is skipped
System.setProperty("fabric.loom.ci", "false")
}
@SuppressWarnings('unused')
def cleanup() {
// Clean after each test
new File(testProjectDir, "build").deleteDir()
new File(testProjectDir, ".gradle").deleteDir()
}
@SuppressWarnings('unused')
def cleanupSpec() {
testProjectDir.deleteDir()
gradleHome.deleteDir()
}
File buildGradle() {
return new File(testProjectDir, "build.gradle")
}
def filesReady() {
}
BuildResult create(String task, String gradleVersion = DEFAULT_GRADLE) {
System.setProperty("fabric.loom.test", "true")
copyInputFiles()
filesReady()
GradleRunner.create()
.withProjectDir(testProjectDir)
.withArguments(task, "--stacktrace", "--warning-mode", warningMode(gradleVersion), "--gradle-user-home", gradleHomeDirectory(gradleVersion))
.withPluginClasspath()
.withGradleVersion(gradleVersion)
.forwardOutput()
.withDebug(true)
.build()
}
String warningMode(String gradleVersion) {
'fail'
}
String gradleHomeDirectory(String gradleVersion) {
// Each gradle version gets its own dir to run on, to ensure that a full run is done.
new File(gradleHome, gradleVersion).absolutePath
}
File getOutputFile(String name, String project = "") {
def file = new File(testProjectDir, "${project}build/libs/${name}")
if (!file.exists()) {
throw new FileNotFoundException("Could not find ${name} at ${file.absolutePath}")
}
return file
}
File getGeneratedSources(String mappings, String gradleVersion = DEFAULT_GRADLE) {
return new File(gradleHomeDirectory(gradleVersion), "caches/fabric-loom/${mappings}/minecraft-mapped-sources.jar")
}
}

View File

@ -0,0 +1,208 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2016-2021 FabricMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.fabricmc.loom.test.util
import groovy.transform.Immutable
import java.util.concurrent.TimeUnit
class ServerRunner {
static final String LOADER_VERSION = "0.11.6"
static final Map<String, String> FABRIC_API_URLS = [
"1.16.5": "https://github.com/FabricMC/fabric/releases/download/0.37.1%2B1.16/fabric-api-0.37.1+1.16.jar",
"1.17.1": "https://github.com/FabricMC/fabric/releases/download/0.37.1%2B1.17/fabric-api-0.37.1+1.17.jar"
]
final File serverDir
final String minecraftVersion
final List<File> mods = []
private ServerRunner(File serverDir, String minecraftVersion) {
this.serverDir = serverDir
this.minecraftVersion = minecraftVersion
this.serverDir.mkdirs()
}
static ServerRunner create(File testProjectDir, String minecraftVersion) {
return new ServerRunner(new File(testProjectDir, "server"), minecraftVersion)
}
def install() {
def args = [
"server",
"-dir",
serverDir.absolutePath,
"-mcversion",
minecraftVersion,
"-loader",
LOADER_VERSION,
"-downloadMinecraft"
]
//noinspection UnnecessaryQualifiedReference
net.fabricmc.installer.Main.main(args as String[])
def eulaFile = new File(serverDir, "eula.txt")
eulaFile << "eula=true"
def serverPropsFile = new File(serverDir, "server.properties")
serverPropsFile << "level-type=FLAT" // Generates the world faster
}
ServerRunner withMod(File file) {
mods << file
return this
}
ServerRunner downloadMod(String url, String filename) {
File modFile = new File(serverDir, "downloadedMods/" + filename)
modFile.parentFile.mkdirs()
println("Downloading " + url)
modFile.bytes = new URL(url).bytes
return withMod(modFile)
}
ServerRunner withFabricApi() {
if (!FABRIC_API_URLS[minecraftVersion]) {
throw new UnsupportedOperationException("No Fabric api url for " + minecraftVersion)
}
return downloadMod(FABRIC_API_URLS[minecraftVersion], "fabricapi.jar")
}
ServerRunResult run() {
install()
// Copy the mods here so we can
mods.each {
if (!it.exists()) {
throw new FileNotFoundException(it.absolutePath)
}
File modFile = new File(serverDir, "mods/" + it.name)
modFile.parentFile.mkdirs()
modFile.bytes = it.bytes
}
String javaExecutablePath = ProcessHandle.current()
.info()
.command()
.orElseThrow()
var builder = new ProcessBuilder()
builder.directory(serverDir)
builder.command(javaExecutablePath, "-Xmx1G", "-jar", "fabric-server-launch.jar", "nogui")
Process process = builder.start()
def out = new StringBuffer()
def isStopping = false
process.consumeProcessOutput(
new ForwardingAppendable([System.out, out], {
if (!isStopping && out.contains("Done ") && out.contains("For help, type \"help\"")) {
isStopping = true
Thread.start {
println("Stopping server in 5 seconds")
sleep(5000)
println("Sending stop command")
process.outputStream.withCloseable {
it.write("stop\n".bytes)
}
}
}
}),
new ForwardingAppendable([System.err, out])
)
addShutdownHook {
if (process.alive) {
process.destroy()
}
}
assert process.waitFor(10, TimeUnit.MINUTES)
int exitCode = process.exitValue()
println("Sever closed with exit code: " + exitCode)
return new ServerRunResult(exitCode, out.toString())
}
@Immutable
class ServerRunResult {
int exitCode
String output
boolean successful() {
return exitCode == 0 && output.contains("Done ")
}
}
private class ForwardingAppendable implements Appendable {
final List<Appendable> appendables
final Closure onAppended
ForwardingAppendable(List<Appendable> appendables, Closure onAppended = {}) {
this.appendables = appendables
this.onAppended = onAppended
}
@Override
Appendable append(CharSequence csq) throws IOException {
appendables.each {
it.append(csq)
}
onAppended.run()
return this
}
@Override
Appendable append(CharSequence csq, int start, int end) throws IOException {
appendables.each {
it.append(csq, start, end)
}
onAppended.run()
return this
}
@Override
Appendable append(char c) throws IOException {
appendables.each {
it.append(c)
}
onAppended.run()
return this
}
}
}

View File

@ -9,6 +9,6 @@ public class ExampleMod implements ModInitializer {
// However, some things (like resources) may still be uninitialized. // However, some things (like resources) may still be uninitialized.
// Proceed with mild caution. // Proceed with mild caution.
System.out.println("Hello Fabric world!"); System.out.println("Hello simple Fabric mod");
} }
} }