From 80665fbf071dc8de7c1f4fe6f79eac248c20559d Mon Sep 17 00:00:00 2001 From: SettingDust Date: Mon, 7 Oct 2024 13:30:53 +0800 Subject: [PATCH 1/4] feat: prefer the loader by order in lock file --- .../kotlin/teksturepako/pakku/api/platforms/CurseForge.kt | 8 +++++++- .../kotlin/teksturepako/pakku/api/platforms/Modrinth.kt | 5 ++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/commonMain/kotlin/teksturepako/pakku/api/platforms/CurseForge.kt b/src/commonMain/kotlin/teksturepako/pakku/api/platforms/CurseForge.kt index 6cd3e8a2..98443f10 100644 --- a/src/commonMain/kotlin/teksturepako/pakku/api/platforms/CurseForge.kt +++ b/src/commonMain/kotlin/teksturepako/pakku/api/platforms/CurseForge.kt @@ -124,8 +124,14 @@ object CurseForge : Platform( .filter { it.gameVersionTypeId == LOADER_VERSION_TYPE_ID } // Filter to loader only .takeIf { it.isNotEmpty() } ?.map { it.gameVersionName.lowercase() }?.any { - loaders.any { loader -> loader == it } || it in validLoaders // Check default valid loaders + it in loaders || it in validLoaders // Check default valid loaders } ?: true // If no loaders found, accept model + }.sortedWith { a, b -> + val aVersions = a.sortableGameVersions.filter { it.gameVersionTypeId == LOADER_VERSION_TYPE_ID } + .map { it.gameVersionName.lowercase() } + val bVersions = b.sortableGameVersions.filter { it.gameVersionTypeId == LOADER_VERSION_TYPE_ID } + .map { it.gameVersionName.lowercase() } + loaders.indexOfFirst { it in aVersions } - loaders.indexOfFirst { it in bVersions } } private fun CfModModel.File.toProjectFile(gameVersionTypeIds: List): ProjectFile diff --git a/src/commonMain/kotlin/teksturepako/pakku/api/platforms/Modrinth.kt b/src/commonMain/kotlin/teksturepako/pakku/api/platforms/Modrinth.kt index 8ea98583..e66a99c2 100644 --- a/src/commonMain/kotlin/teksturepako/pakku/api/platforms/Modrinth.kt +++ b/src/commonMain/kotlin/teksturepako/pakku/api/platforms/Modrinth.kt @@ -139,9 +139,12 @@ object Modrinth : Platform( version.gameVersions.any { it in mcVersions } && version.loaders .takeIf { it.isNotEmpty() } ?.map { it.lowercase() }?.any { - loaders.any { loader -> loader == it } || it in validLoaders // Check default valid loaders + it in loaders || it in validLoaders // Check default valid loaders } ?: true // If no loaders found, accept model } + .sortedWith { a, b -> + loaders.indexOfFirst { it in a.loaders } - loaders.indexOfFirst { it in b.loaders } + } private fun MrVersionModel.toProjectFiles(): List { From db43413fb447556d5fc87020ee57e4fe5034caab Mon Sep 17 00:00:00 2001 From: SettingDust Date: Mon, 7 Oct 2024 14:15:25 +0800 Subject: [PATCH 2/4] fix: sort the order after sort by date --- .../teksturepako/pakku/api/platforms/CurseForge.kt | 12 ++++++++---- .../teksturepako/pakku/api/platforms/Modrinth.kt | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/commonMain/kotlin/teksturepako/pakku/api/platforms/CurseForge.kt b/src/commonMain/kotlin/teksturepako/pakku/api/platforms/CurseForge.kt index 98443f10..526076a1 100644 --- a/src/commonMain/kotlin/teksturepako/pakku/api/platforms/CurseForge.kt +++ b/src/commonMain/kotlin/teksturepako/pakku/api/platforms/CurseForge.kt @@ -121,12 +121,14 @@ object CurseForge : Platform( ): List = this .filter { file -> file.gameVersions.any { it in mcVersions } && file.sortableGameVersions - .filter { it.gameVersionTypeId == LOADER_VERSION_TYPE_ID } // Filter to loader only + .filter { it.gameVersionTypeId == LOADER_VERSION_TYPE_ID } .takeIf { it.isNotEmpty() } ?.map { it.gameVersionName.lowercase() }?.any { - it in loaders || it in validLoaders // Check default valid loaders - } ?: true // If no loaders found, accept model - }.sortedWith { a, b -> + it in loaders || it in validLoaders + } ?: true + } + + private fun List.sortByLoaders(loaders: List) = this.sortedWith { a, b -> val aVersions = a.sortableGameVersions.filter { it.gameVersionTypeId == LOADER_VERSION_TYPE_ID } .map { it.gameVersionName.lowercase() } val bVersions = b.sortableGameVersions.filter { it.gameVersionTypeId == LOADER_VERSION_TYPE_ID } @@ -198,6 +200,7 @@ object CurseForge : Platform( this.requestProjectBody(requestUrl) ?: return mutableSetOf() ).data .filterFileModels(mcVersions, loaders) + .sortByLoaders(loaders) .map { it.toProjectFile(gameVersionTypeIds) } .debugIfEmpty { println("${this::class.simpleName}#requestProjectFiles: file is null") @@ -229,6 +232,7 @@ object CurseForge : Platform( ).data .filterFileModels(mcVersions, loaders) .sortedByDescending { it.fileDate } + .sortByLoaders(loaders) .map { it.toProjectFile(gameVersionTypeIds) } .debugIfEmpty { println("${this::class.simpleName}#requestMultipleProjectFiles: file is null") diff --git a/src/commonMain/kotlin/teksturepako/pakku/api/platforms/Modrinth.kt b/src/commonMain/kotlin/teksturepako/pakku/api/platforms/Modrinth.kt index e66a99c2..f6ed21f1 100644 --- a/src/commonMain/kotlin/teksturepako/pakku/api/platforms/Modrinth.kt +++ b/src/commonMain/kotlin/teksturepako/pakku/api/platforms/Modrinth.kt @@ -14,6 +14,7 @@ import teksturepako.pakku.api.models.mr.GetVersionsFromHashesRequest import teksturepako.pakku.api.models.mr.MrProjectModel import teksturepako.pakku.api.models.mr.MrVersionModel import teksturepako.pakku.api.projects.* +import teksturepako.pakku.debug import teksturepako.pakku.debugIfEmpty import kotlin.system.exitProcess import kotlin.time.Duration.Companion.seconds @@ -142,9 +143,10 @@ object Modrinth : Platform( it in loaders || it in validLoaders // Check default valid loaders } ?: true // If no loaders found, accept model } - .sortedWith { a, b -> - loaders.indexOfFirst { it in a.loaders } - loaders.indexOfFirst { it in b.loaders } - } + + private fun List.sortByLoaders(loaders: List) = this.sortedWith { a, b -> + loaders.indexOfFirst { it in a.loaders } - loaders.indexOfFirst { it in b.loaders } + } private fun MrVersionModel.toProjectFiles(): List { @@ -185,6 +187,7 @@ object Modrinth : Platform( this.requestProjectBody("project/$projectId/version") ?: return mutableSetOf() ) .filterFileModels(mcVersions, loaders) + .sortByLoaders(loaders) .flatMap { version -> version.toProjectFiles() } .debugIfEmpty { println("${this::class.simpleName}#requestProjectFiles: file is null") @@ -216,8 +219,9 @@ object Modrinth : Platform( } .awaitAll() .flatten() - .sortedByDescending { it.datePublished } .filterFileModels(mcVersions, loaders) + .sortedByDescending { it.datePublished } + .sortByLoaders(loaders) .flatMap { version -> version.toProjectFiles() } .toMutableSet() } From 28b39da5c419806a64b8e9e7ff30813529b918c0 Mon Sep 17 00:00:00 2001 From: SettingDust Date: Tue, 8 Oct 2024 09:31:56 +0800 Subject: [PATCH 3/4] fix: consider non-exist loader for `sortByLoaders` - add tests for `sortByLoaders` --- build.gradle.kts | 1 + .../pakku/api/platforms/CurseForge.kt | 23 ++-- .../pakku/api/platforms/Modrinth.kt | 5 +- .../pakku/api/platforms/CurseForgeTest.kt | 118 ++++++++++++++++++ .../pakku/api/platforms/ModrinthTest.kt | 69 ++++++++++ 5 files changed, 203 insertions(+), 13 deletions(-) create mode 100644 src/commonTest/kotlin/teksturepako/pakku/api/platforms/ModrinthTest.kt diff --git a/build.gradle.kts b/build.gradle.kts index 9ce3d74e..93fb8182 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -99,6 +99,7 @@ kotlin { val commonTest by getting { dependencies { implementation(kotlin("test")) + implementation("io.mockk:mockk:1.13.12") } } diff --git a/src/commonMain/kotlin/teksturepako/pakku/api/platforms/CurseForge.kt b/src/commonMain/kotlin/teksturepako/pakku/api/platforms/CurseForge.kt index 526076a1..2a015912 100644 --- a/src/commonMain/kotlin/teksturepako/pakku/api/platforms/CurseForge.kt +++ b/src/commonMain/kotlin/teksturepako/pakku/api/platforms/CurseForge.kt @@ -114,9 +114,9 @@ object CurseForge : Platform( // -- FILES -- - private const val LOADER_VERSION_TYPE_ID = 68441 + internal const val LOADER_VERSION_TYPE_ID = 68441 - private fun List.filterFileModels( + internal fun List.filterFileModels( mcVersions: List, loaders: List ): List = this .filter { file -> @@ -124,17 +124,18 @@ object CurseForge : Platform( .filter { it.gameVersionTypeId == LOADER_VERSION_TYPE_ID } .takeIf { it.isNotEmpty() } ?.map { it.gameVersionName.lowercase() }?.any { - it in loaders || it in validLoaders - } ?: true + it in loaders || it in validLoaders // Check default valid loaders + } ?: true // If no loaders found, accept model } - private fun List.sortByLoaders(loaders: List) = this.sortedWith { a, b -> - val aVersions = a.sortableGameVersions.filter { it.gameVersionTypeId == LOADER_VERSION_TYPE_ID } - .map { it.gameVersionName.lowercase() } - val bVersions = b.sortableGameVersions.filter { it.gameVersionTypeId == LOADER_VERSION_TYPE_ID } - .map { it.gameVersionName.lowercase() } - loaders.indexOfFirst { it in aVersions } - loaders.indexOfFirst { it in bVersions } - } + internal fun List.sortByLoaders(loaders: List) = this.sortedWith { fileA, fileB -> + val aLoaders = fileA.sortableGameVersions.filter { it.gameVersionTypeId == LOADER_VERSION_TYPE_ID } + .map { it.gameVersionName.lowercase() } + val bLoaders = fileB.sortableGameVersions.filter { it.gameVersionTypeId == LOADER_VERSION_TYPE_ID } + .map { it.gameVersionName.lowercase() } + loaders.indexOfFirst { it in aLoaders }.let { if (it == -1) loaders.size else it } + .minus(loaders.indexOfFirst { it in bLoaders }.let { if (it == -1) loaders.size else it }) + } private fun CfModModel.File.toProjectFile(gameVersionTypeIds: List): ProjectFile { diff --git a/src/commonMain/kotlin/teksturepako/pakku/api/platforms/Modrinth.kt b/src/commonMain/kotlin/teksturepako/pakku/api/platforms/Modrinth.kt index f6ed21f1..4f659300 100644 --- a/src/commonMain/kotlin/teksturepako/pakku/api/platforms/Modrinth.kt +++ b/src/commonMain/kotlin/teksturepako/pakku/api/platforms/Modrinth.kt @@ -144,8 +144,9 @@ object Modrinth : Platform( } ?: true // If no loaders found, accept model } - private fun List.sortByLoaders(loaders: List) = this.sortedWith { a, b -> - loaders.indexOfFirst { it in a.loaders } - loaders.indexOfFirst { it in b.loaders } + internal fun List.sortByLoaders(loaders: List) = this.sortedWith { aVersion, bVersion -> + loaders.indexOfFirst { it in aVersion.loaders }.let { if (it == -1) loaders.size else it } + .minus(loaders.indexOfFirst { it in bVersion.loaders }.let { if (it == -1) loaders.size else it }) } private fun MrVersionModel.toProjectFiles(): List diff --git a/src/commonTest/kotlin/teksturepako/pakku/api/platforms/CurseForgeTest.kt b/src/commonTest/kotlin/teksturepako/pakku/api/platforms/CurseForgeTest.kt index 58db8d7e..0f94ae94 100644 --- a/src/commonTest/kotlin/teksturepako/pakku/api/platforms/CurseForgeTest.kt +++ b/src/commonTest/kotlin/teksturepako/pakku/api/platforms/CurseForgeTest.kt @@ -1,6 +1,13 @@ package teksturepako.pakku.api.platforms +import io.mockk.every +import io.mockk.mockk +import teksturepako.pakku.api.models.cf.CfModModel +import teksturepako.pakku.api.platforms.CurseForge.LOADER_VERSION_TYPE_ID +import teksturepako.pakku.api.platforms.CurseForge.sortByLoaders import kotlin.test.Test +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals class CurseForgeTest { @@ -8,4 +15,115 @@ class CurseForgeTest fun requestProject() { } + + @Test + fun sortByLoaders_WithValidLoaders_ShouldSortCorrectly() { + val files = listOf( + mockk { + every { sortableGameVersions } returns listOf( + mockk { + every { gameVersionTypeId } returns LOADER_VERSION_TYPE_ID + every { gameVersionName } returns "loaderB" + }, + mockk { + every { gameVersionTypeId } returns LOADER_VERSION_TYPE_ID + every { gameVersionName } returns "loaderC" + } + ) + }, + mockk { + every { sortableGameVersions } returns listOf( + mockk { + every { gameVersionTypeId } returns LOADER_VERSION_TYPE_ID + every { gameVersionName } returns "loaderA" + }, + mockk { + every { gameVersionTypeId } returns LOADER_VERSION_TYPE_ID + every { gameVersionName } returns "loaderB" + } + ) + }, + mockk { + every { sortableGameVersions } returns listOf( + mockk { + every { gameVersionTypeId } returns LOADER_VERSION_TYPE_ID + every { gameVersionName } returns "loaderB" + }, + mockk { + every { gameVersionTypeId } returns LOADER_VERSION_TYPE_ID + every { gameVersionName } returns "loaderB" + } + ) + }, + mockk { + every { sortableGameVersions } returns listOf( + mockk { + every { gameVersionTypeId } returns LOADER_VERSION_TYPE_ID + every { gameVersionName } returns "loaderA" + }, + mockk { + every { gameVersionTypeId } returns LOADER_VERSION_TYPE_ID + every { gameVersionName } returns "loaderC" + } + ) + } + ) + + val loaders = listOf("loadera", "loaderb", "loaderc") + val sortedFiles = files.toList().sortByLoaders(loaders) + + assertContentEquals(listOf(files[1], files[3], files[0], files[2]), sortedFiles) + } + + @Test + fun sortByLoaders_WithNoMatchingLoaders_ShouldNotChangeOrder() { + val files = listOf( + mockk { + every { sortableGameVersions } returns listOf( + mockk { + every { gameVersionTypeId } returns LOADER_VERSION_TYPE_ID + every { gameVersionName } returns "loaderB" + } + ) + }, + mockk { + every { sortableGameVersions } returns listOf( + mockk { + every { gameVersionTypeId } returns LOADER_VERSION_TYPE_ID + every { gameVersionName } returns "loaderA" + } + ) + } + ) + + val loaders = listOf("loader1", "loader2") + val sortedFiles = files.toList().sortByLoaders(loaders) + assertContentEquals(files, sortedFiles) + } + + @Test + fun sortByLoaders_WithSomeMatchingLoaders_ShouldSortCorrectly() { + val files = listOf( + mockk { + every { sortableGameVersions } returns listOf( + mockk { + every { gameVersionTypeId } returns LOADER_VERSION_TYPE_ID + every { gameVersionName } returns "loaderA" + } + ) + }, + mockk { + every { sortableGameVersions } returns listOf( + mockk { + every { gameVersionTypeId } returns LOADER_VERSION_TYPE_ID + every { gameVersionName } returns "loader1" + } + ) + } + ) + + val loaders = listOf("loader1", "loader2") + val sortedFiles = files.toList().sortByLoaders(loaders) + assertEquals(files[0], sortedFiles[1]) + } } \ No newline at end of file diff --git a/src/commonTest/kotlin/teksturepako/pakku/api/platforms/ModrinthTest.kt b/src/commonTest/kotlin/teksturepako/pakku/api/platforms/ModrinthTest.kt new file mode 100644 index 00000000..d841460c --- /dev/null +++ b/src/commonTest/kotlin/teksturepako/pakku/api/platforms/ModrinthTest.kt @@ -0,0 +1,69 @@ +package teksturepako.pakku.api.platforms + +import io.mockk.every +import io.mockk.mockk +import teksturepako.pakku.api.models.mr.MrVersionModel +import teksturepako.pakku.api.platforms.Modrinth.sortByLoaders +import kotlin.test.Test +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals + +class ModrinthTest +{ + @Test + fun sortByLoaders_WithValidLoaders_ShouldSortCorrectly() { + val versions = listOf( + mockk { + every { loaders } returns listOf("loaderb", "loaderc") + }, + mockk { + every { loaders } returns listOf("loadera", "loaderb") + }, + mockk { + every { loaders } returns listOf("loaderb", "loaderb") + }, + mockk { + every { loaders } returns listOf("loadera", "loaderc") + } + ) + + val loaders = listOf("loadera", "loaderb", "loaderc") + val sortedVersions = versions.toList().sortByLoaders(loaders) + + assertContentEquals(listOf(versions[1], versions[3], versions[0], versions[2]), sortedVersions) + } + + @Test + fun sortByLoaders_WithNoMatchingLoaders_ShouldNotChangeOrder() { + val versions = listOf( + mockk { + every { loaders } returns listOf("loaderB") + }, + mockk { + every { loaders } returns listOf("loaderA") + } + ) + + val loaders = listOf("loader1", "loader2") + val sortedVersions = versions.toList().sortByLoaders(loaders) + + assertContentEquals(versions, sortedVersions) + } + + @Test + fun sortByLoaders_WithSomeMatchingLoaders_ShouldSortCorrectly() { + val versions = listOf( + mockk { + every { loaders } returns listOf("loadera") + }, + mockk { + every { loaders } returns listOf("loader1") + } + ) + + val loaders = listOf("loader1", "loader2") + val sortedVersions = versions.toList().sortByLoaders(loaders) + + assertEquals(versions[0], sortedVersions[1]) + } +} \ No newline at end of file From 1f5403a2b326cb2f976a95243211d3095c9ff7a8 Mon Sep 17 00:00:00 2001 From: SettingDust Date: Tue, 8 Oct 2024 09:36:00 +0800 Subject: [PATCH 4/4] revert: wrong changes --- .../kotlin/teksturepako/pakku/api/platforms/CurseForge.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commonMain/kotlin/teksturepako/pakku/api/platforms/CurseForge.kt b/src/commonMain/kotlin/teksturepako/pakku/api/platforms/CurseForge.kt index 2a015912..0437e9f2 100644 --- a/src/commonMain/kotlin/teksturepako/pakku/api/platforms/CurseForge.kt +++ b/src/commonMain/kotlin/teksturepako/pakku/api/platforms/CurseForge.kt @@ -116,12 +116,12 @@ object CurseForge : Platform( internal const val LOADER_VERSION_TYPE_ID = 68441 - internal fun List.filterFileModels( + private fun List.filterFileModels( mcVersions: List, loaders: List ): List = this .filter { file -> file.gameVersions.any { it in mcVersions } && file.sortableGameVersions - .filter { it.gameVersionTypeId == LOADER_VERSION_TYPE_ID } + .filter { it.gameVersionTypeId == LOADER_VERSION_TYPE_ID } // Filter to loader only .takeIf { it.isNotEmpty() } ?.map { it.gameVersionName.lowercase() }?.any { it in loaders || it in validLoaders // Check default valid loaders