Skip to content

Commit

Permalink
Fabric import test
Browse files Browse the repository at this point in the history
  • Loading branch information
RedNesto committed Aug 13, 2024
1 parent 9a0e92b commit 67896da
Show file tree
Hide file tree
Showing 5 changed files with 401 additions and 71 deletions.
46 changes: 46 additions & 0 deletions src/main/kotlin/creator/maven-repo-utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,52 @@ suspend fun collectMavenVersions(url: String, filter: Predicate<String> = Predic
return result
}

data class MavenLatestAndReleaseVersion(val latest: String?, val release: String?)

@Throws(IOException::class)
suspend fun collectMavenLatestAndReleaseVersion(url: String): MavenLatestAndReleaseVersion {
val manager = FuelManager()
manager.proxy = selectProxy(url)

val response = manager.get(url)
.header("User-Agent", PluginUtil.useragent)
.allowRedirects(true)
.suspendable()
.await()

var latest: String? = null
var release: String? = null
response.body().toStream().use { stream ->
val inputFactory = XMLInputFactory.newInstance()

@Suppress("UNCHECKED_CAST")
val reader = inputFactory.createXMLEventReader(stream) as Iterator<XMLEvent>
for (event in reader) {
if (!event.isStartElement) {
continue
}
val start = event.asStartElement()
val name = start.name.localPart
if (name != "latest" && name != "release") {
continue
}

val versionEvent = reader.next()
if (!versionEvent.isCharacters) {
continue
}

val version = versionEvent.asCharacters().data
when (name) {
"latest" -> latest = version
"release" -> release = version
}
}
}

return MavenLatestAndReleaseVersion(latest, release)
}

@Throws(IOException::class)
suspend fun scrapeArtifactoryDirectoryListing(url: String): List<String> {
val manager = FuelManager()
Expand Down
6 changes: 6 additions & 0 deletions src/main/kotlin/platform/fabric/FabricModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ class FabricModule internal constructor(facet: MinecraftFacet) : AbstractModule(
var fabricJson by nullable { facet.findFile(FabricConstants.FABRIC_MOD_JSON, SourceType.RESOURCE) }
private set

val loomData: FabricLoomData?
get() {
val gradleData = GradleUtil.findGradleModuleData(facet.module) ?: return null
return gradleData.children.find { it.key == FabricLoomData.KEY }?.data as? FabricLoomData
}

private var namedToMojangManagerField: MappingsManager? = null
override val namedToMojangManager: MappingsManager?
get() = namedToMojangManagerField
Expand Down
125 changes: 125 additions & 0 deletions src/test/kotlin/framework/GradleImportTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* Minecraft Development for IntelliJ
*
* https://mcdev.io/
*
* Copyright (C) 2024 minecraft-dev
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, version 3.0 only.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package com.demonwav.mcdev.framework

import com.demonwav.mcdev.facet.MinecraftFacet
import com.demonwav.mcdev.platform.AbstractModule
import com.demonwav.mcdev.platform.AbstractModuleType
import com.demonwav.mcdev.platform.PlatformType
import com.demonwav.mcdev.util.runWriteTask
import com.intellij.openapi.externalSystem.model.ProjectSystemId
import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.modules
import com.intellij.openapi.projectRoots.JavaSdk
import com.intellij.openapi.projectRoots.ProjectJdkTable
import com.intellij.openapi.projectRoots.ex.JavaSdkUtil
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.platform.externalSystem.testFramework.ExternalSystemImportingTestCase
import java.nio.file.FileSystemException
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
import org.jetbrains.plugins.gradle.util.GradleConstants
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.TestInfo

/**
* Based on https://github.com/JetBrains/intellij-community/blob/a1c5c737ba52cd5810c95d28e6e685d11958844b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleImportingTestCase.java
*/
abstract class BaseGradleImportTest : ExternalSystemImportingTestCase() {

companion object {
const val GRADLE_WRAPPER_PROPERTIES = "gradle/wrapper/gradle-wrapper.properties"
const val BUILD_GRADLE = "build.gradle"
const val BUILD_GRADLE_KT = "build.gradle.kts"
const val GRADLE_PROPERTIES = "build.gradle"
const val SETTINGS_GRADLE = "settings.gradle"
}

private val projectSettings = GradleProjectSettings().withQualifiedModuleNames()

override fun getCurrentExternalProjectSettings(): ExternalProjectSettings? = projectSettings

override fun getExternalSystemId(): ProjectSystemId? = GradleConstants.SYSTEM_ID

override fun getTestsTempDir(): String? = "tmp"

override fun getExternalSystemConfigFileName(): String? = "build.gradle"

@BeforeEach
@Suppress("JUnitMalformedDeclaration") // Hey JetBrains, it's working fine...
fun setUp(testInfo: TestInfo) {
name = testInfo.displayName
super.setUp()

runWriteTask {
val jdk21Home = System.getenv("JDK_21_0") ?: System.getenv("JDK_21") ?: System.getenv("JDK21")
assertNotNull("Could not find JDK 21 home", jdk21Home)

val jdk = JavaSdk.getInstance().createJdk("JDK 21", jdk21Home, false)
ProjectJdkTable.getInstance().addJdk(jdk)
JavaSdkUtil.applyJdkToProject(myProject, jdk)
}
}

@AfterEach
override fun tearDown() {
runWriteTask {
val sdk = ProjectRootManager.getInstance(myProject).projectSdk
ProjectRootManager.getInstance(myProject).projectSdk = null
if (sdk != null) {
ProjectJdkTable.getInstance().removeJdk(sdk)
}
}

try {
super.tearDown()
} catch (e: FileSystemException) {
// This is a frequent issue on Windows, but is harmless, except the fact it leaves the culprit file existing
println("Ignoring FSException: ${e.message}")
}
}

protected fun findModule(name: String): Module {
val module = myProject.modules.find { it.name.contains(name) }
assertNotNull("Could not find module containing '$name'", module)
return module!!
}

protected fun findMainModule() = findModule("main")

protected fun Module.assertDetectedPlatformTypes(vararg platformTypes: PlatformType) {
val facet = MinecraftFacet.getInstance(this)
assertNotNull("MinecraftFacet is null in module ${this.name}", facet)

assertSameElements(facet!!.configuration.state.autoDetectTypes, platformTypes.toSet())
}

protected fun <T : AbstractModule> Module.assertMinecraftModule(moduleType: AbstractModuleType<T>): T {
val facet = MinecraftFacet.getInstance(this)
assertNotNull("MinecraftFacet is null in module ${this.name}", facet)

val module = facet!!.getModuleOfType(moduleType)
assertNotNull("Could not find Minecraft module of type ${moduleType.javaClass.name}", module)

return module!!
}
}
193 changes: 193 additions & 0 deletions src/test/kotlin/platform/fabric/FabricImportTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
/*
* Minecraft Development for IntelliJ
*
* https://mcdev.io/
*
* Copyright (C) 2024 minecraft-dev
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, version 3.0 only.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package com.demonwav.mcdev.platform.fabric

import com.demonwav.mcdev.creator.collectMavenLatestAndReleaseVersion
import com.demonwav.mcdev.framework.BaseGradleImportTest
import com.demonwav.mcdev.platform.PlatformType
import com.demonwav.mcdev.platform.mcp.McpModuleType
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.DisplayName
import org.junitpioneer.jupiter.cartesian.ArgumentSets
import org.junitpioneer.jupiter.cartesian.CartesianTest

@DisplayName("Fabric Import Tests")
class FabricImportTest : BaseGradleImportTest() {

private fun prepareTest(
loomVersion: String,
minecraftVersion: String,
yarnMappings: String,
loaderVersion: String,
splitSources: Boolean,
) {
createProjectSubFile(
GRADLE_WRAPPER_PROPERTIES,
"distributionUrl=https://services.gradle.org/distributions/gradle-8.8-bin.zip"
)

createProjectSubFile(
BUILD_GRADLE,
"""
plugins {
id 'fabric-loom' version '$loomVersion'
}
loom {
${if (splitSources) "splitEnvironmentSourceSets()" else ""}
mods {
"test-mod" {
sourceSet sourceSets.main
${if (splitSources) "sourceSet sourceSets.client" else ""}
}
}
}
dependencies {
minecraft "com.mojang:minecraft:$minecraftVersion"
mappings "net.fabricmc:yarn:$yarnMappings:v2"
modImplementation "net.fabricmc:fabric-loader:$loaderVersion"
}
""".trimIndent()
)

createProjectSubFile(
SETTINGS_GRADLE,
"""
pluginManagement {
repositories {
maven {
name = 'Fabric'
url = 'https://maven.fabricmc.net/'
}
gradlePluginPortal()
}
}
"""
)

importProject(true)
importProject(true) // Import twice otherwise McpModule settings won't be populated properly
}

@CartesianTest
@CartesianTest.MethodFactory("argumentsFactory")
fun fabricImportedData(
loomVersion: String,
fabricVersions: TestVersions,
splitSources: Boolean,
) {
prepareTest(loomVersion, fabricVersions.mc, fabricVersions.yarn, fabricVersions.loader, splitSources)

val module = findMainModule()
module.assertDetectedPlatformTypes(PlatformType.FABRIC, PlatformType.MCP, PlatformType.MIXIN)

val mcpModule = module.assertMinecraftModule(McpModuleType)
val mcpSettings = mcpModule.getSettings()
assertEquals(mcpSettings.minecraftVersion, fabricVersions.mc)

val fabricModule = module.assertMinecraftModule(FabricModuleType)
val loomData = fabricModule.loomData
assertNotNull(loomData)

assertNotNull(loomData!!.tinyMappings)
assertTrue(loomData.tinyMappings!!.exists())
assertTrue(loomData.tinyMappings!!.isFile())

val expectedDecompilers = setOf("cfr", "fernFlower", "vineflower")

if (splitSources) {
assertTrue(loomData.splitMinecraftJar)

// SourceSets
val modSourceSets = loomData.modSourceSets
assertNotNull(modSourceSets)
assertEquals(1, modSourceSets!!.size)

val testModSourceSets = modSourceSets["test-mod"]
assertNotNull(testModSourceSets)
assertContainsElements(testModSourceSets!!, "main", "client")

// Decompilers
val decompilers = loomData.decompileTasks
assertNotNull(decompilers)
assertEquals(2, decompilers.size)

val commonDecompilers = decompilers["common"]
assertNotNull(commonDecompilers)
assertTrue(commonDecompilers!!.all { it.name in expectedDecompilers })

val clientDecompilers = decompilers["client"]
assertNotNull(clientDecompilers)
assertTrue(clientDecompilers!!.all { it.name in expectedDecompilers })
} else {
assertFalse(loomData.splitMinecraftJar)

// SourceSets
val modSourceSets = loomData.modSourceSets
assertNotNull(modSourceSets)
assertEquals(1, modSourceSets!!.size)

val testModSourceSets = modSourceSets["test-mod"]
assertNotNull(testModSourceSets)
assertContainsElements(testModSourceSets!!, "main")

// Decompilers
val decompilers = loomData.decompileTasks
assertNotNull(decompilers)
assertEquals(1, decompilers.size)

val singleDecompilers = decompilers["single"]
assertNotNull(singleDecompilers)
assertTrue(singleDecompilers!!.all { it.name in expectedDecompilers })
}
}

data class TestVersions(val mc: String, val yarn: String, val loader: String)

companion object {
@JvmStatic
@Suppress("unused") // Used in @CartesianTest.MethodFactory
fun argumentsFactory(): ArgumentSets {
val loomVersions = runBlocking {
collectMavenLatestAndReleaseVersion(
"https://maven.fabricmc.net/fabric-loom/fabric-loom.gradle.plugin/maven-metadata.xml"
)
}

return ArgumentSets.argumentsForFirstParameter(
loomVersions.latest,
"1.7-SNAPSHOT",
"1.6-SNAPSHOT",
"1.5-SNAPSHOT",
"1.4-SNAPSHOT",
"1.3-SNAPSHOT",
).argumentsForNextParameter(
TestVersions("1.21.1", "1.21.1+build.3", "0.16.0"),
TestVersions("1.21", "1.21+build.9", "0.16.0"),
TestVersions("1.20.6", "1.20.6+build.3", "0.16.0"),
TestVersions("1.19.4", "1.19.4+build.2", "0.16.0"),
TestVersions("1.18.2", "1.18.2+build.4", "0.16.0"),
).argumentsForNextParameter(true, false)
}
}
}
Loading

0 comments on commit 67896da

Please sign in to comment.