[KLIB] ABI reader: Refactor manifest reading test

^KT-54402
diff --git a/compiler/util-klib-abi/test/org/jetbrains/kotlin/library/abi/ManifestReadingTest.kt b/compiler/util-klib-abi/test/org/jetbrains/kotlin/library/abi/ManifestReadingTest.kt
new file mode 100644
index 0000000..3d7a54a
--- /dev/null
+++ b/compiler/util-klib-abi/test/org/jetbrains/kotlin/library/abi/ManifestReadingTest.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.library.abi
+
+import com.intellij.openapi.util.io.FileUtil.createTempDirectory
+import org.jetbrains.kotlin.library.*
+import org.jetbrains.kotlin.library.impl.BuiltInsPlatform
+import org.jetbrains.kotlin.library.impl.KotlinLibraryLayoutForWriter
+import org.jetbrains.kotlin.library.impl.KotlinLibraryWriterImpl
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Assertions.assertTrue
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.TestInfo
+import java.io.File
+import java.util.*
+import org.jetbrains.kotlin.konan.file.File as KFile
+
+@OptIn(ExperimentalLibraryAbiReader::class)
+class ManifestReadingTest {
+    private lateinit var buildDir: File
+
+    @BeforeEach
+    fun setUp(testInfo: TestInfo) {
+        buildDir = createTempDirectory(testInfo.testClass.get().simpleName, testInfo.testMethod.get().name)
+    }
+
+    @AfterEach
+    fun tearDown() {
+        buildDir.deleteRecursively()
+    }
+
+    @Test
+    fun testManifestReading() {
+        val testData = mapOf(
+            "sample-library-1" to LibraryManifest(
+                platform = BuiltInsPlatform.JS.name,
+                nativeTargets = emptyList(),
+                compilerVersion = "1.23.45",
+                abiVersion = "2.34.56",
+                libraryVersion = "3.45.67",
+                irProviderName = "test_ir_provider_123"
+            ),
+            "sample-library-2" to LibraryManifest(
+                platform = BuiltInsPlatform.NATIVE.name,
+                nativeTargets = listOf("ios_arm64", "ios_simulator_arm64", "macos_arm64", "macos_x64"),
+                compilerVersion = null,
+                abiVersion = null,
+                libraryVersion = null,
+                irProviderName = null
+            ),
+        )
+
+        testData.forEach { (libraryName, originalManifest) ->
+            val libraryFile = createEmptyLibraryWithSpecificManifest(libraryName, originalManifest)
+            val readManifest = LibraryAbiReader.readAbiInfo(libraryFile).manifest
+
+            assertTrue(originalManifest !== readManifest) { "Library name: $libraryName" }
+            assertEquals(originalManifest, readManifest) { "Library name: $libraryName" }
+        }
+    }
+
+    private fun createEmptyLibraryWithSpecificManifest(libraryName: String, libraryManifest: LibraryManifest): File {
+        val libraryVersioning = KotlinLibraryVersioning(
+            libraryVersion = libraryManifest.libraryVersion,
+            compilerVersion = libraryManifest.compilerVersion,
+            abiVersion = libraryManifest.abiVersion?.parseKotlinAbiVersion(),
+            metadataVersion = null
+        )
+        val builtInsPlatform = libraryManifest.platform?.let(BuiltInsPlatform::parseFromString)
+            ?: error("Unknown platform: ${libraryManifest.platform}")
+
+        val libraryFile = buildDir.resolve("$libraryName.klib")
+        val libraryKFile = KFile(libraryFile.absolutePath)
+
+        val libraryLayout = KotlinLibraryLayoutForWriter(libraryKFile, libraryKFile)
+        val library = KotlinLibraryWriterImpl(
+            moduleName = libraryName,
+            versions = libraryVersioning,
+            builtInsPlatform = builtInsPlatform,
+            nativeTargets = libraryManifest.nativeTargets,
+            nopack = true,
+            shortName = libraryName,
+            layout = libraryLayout
+        )
+        libraryManifest.irProviderName?.let { irProviderName ->
+            library.addManifestAddend(
+                Properties().apply {
+                    this[KLIB_PROPERTY_IR_PROVIDER] = irProviderName
+                }
+            )
+        }
+        library.addIr(SerializedIrModule(files = emptyList())) // Empty library.
+        library.commit()
+
+        return libraryFile
+    }
+}
diff --git a/compiler/util-klib-abi/test/org/jetbrains/kotlin/library/abi/ManifestRenderingTest.kt b/compiler/util-klib-abi/test/org/jetbrains/kotlin/library/abi/ManifestRenderingTest.kt
deleted file mode 100644
index 9c69c5f..0000000
--- a/compiler/util-klib-abi/test/org/jetbrains/kotlin/library/abi/ManifestRenderingTest.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package org.jetbrains.kotlin.library.abi
-
-import org.jetbrains.kotlin.library.impl.BuiltInsPlatform
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.junit.jupiter.api.Assertions.assertTrue
-import org.junit.jupiter.api.BeforeEach
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.TestInfo
-import java.io.File
-
-@OptIn(ExperimentalLibraryAbiReader::class)
-class ManifestRenderingTest {
-    private lateinit var buildDir: File
-    private lateinit var sourceFile: File
-
-    @BeforeEach
-    fun setUp(testInfo: TestInfo) {
-        buildDir = setUpBuildDir(testInfo)
-        sourceFile = buildDir.resolve("source.kt").apply { createNewFile() } // Just an empty file.
-    }
-
-    @Test
-    fun renderWithManifest() {
-        val customManifest = LibraryManifest(
-            platform = BuiltInsPlatform.JS.name,
-            nativeTargets = listOf("ios_arm64", "ios_simulator_arm64", "macos_arm64", "macos_x64"),
-            compilerVersion = "1.23.45",
-            abiVersion = "2.34.56",
-            libraryVersion = "3.45.67",
-            irProviderName = "test_ir_provider_123"
-        )
-
-        val libraryFile = buildLibrary(sourceFile, libraryName = "sample-library", buildDir)
-        patchManifest(libraryFile, customManifest)
-
-        val readManifest = LibraryAbiReader.readAbiInfo(libraryFile).manifest
-        assertTrue(customManifest !== readManifest)
-        assertEquals(customManifest, readManifest)
-    }
-}
diff --git a/compiler/util-klib-abi/test/org/jetbrains/kotlin/library/abi/utils.kt b/compiler/util-klib-abi/test/org/jetbrains/kotlin/library/abi/utils.kt
deleted file mode 100644
index ee73ede..0000000
--- a/compiler/util-klib-abi/test/org/jetbrains/kotlin/library/abi/utils.kt
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package org.jetbrains.kotlin.library.abi
-
-import com.intellij.openapi.vfs.StandardFileSystems
-import com.intellij.openapi.vfs.VirtualFileManager
-import com.intellij.openapi.vfs.local.CoreLocalFileSystem
-import com.intellij.psi.PsiManager
-import com.intellij.psi.SingleRootFileViewProvider
-import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
-import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
-import org.jetbrains.kotlin.cli.js.klib.compileModuleToAnalyzedFirWithPsi
-import org.jetbrains.kotlin.cli.js.klib.serializeFirKlib
-import org.jetbrains.kotlin.cli.js.klib.transformFirToIr
-import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
-import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment.Companion.createForParallelTests
-import org.jetbrains.kotlin.config.CommonConfigurationKeys
-import org.jetbrains.kotlin.config.CompilerConfiguration
-import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
-import org.jetbrains.kotlin.ir.backend.js.MainModule
-import org.jetbrains.kotlin.ir.backend.js.ModulesStructure
-import org.jetbrains.kotlin.js.config.JSConfigurationKeys
-import org.jetbrains.kotlin.konan.file.ZipFileSystemCacheableAccessor
-import org.jetbrains.kotlin.konan.file.unzipTo
-import org.jetbrains.kotlin.konan.file.zipDirAs
-import org.jetbrains.kotlin.konan.properties.saveToFile
-import org.jetbrains.kotlin.library.*
-import org.jetbrains.kotlin.psi.KtFile
-import org.jetbrains.kotlin.serialization.js.ModuleKind
-import org.jetbrains.kotlin.test.utils.TestDisposable
-import org.junit.jupiter.api.Assertions.*
-import org.junit.jupiter.api.TestInfo
-import java.io.ByteArrayOutputStream
-import java.io.File
-import java.io.PrintStream
-import java.nio.charset.Charset
-import org.jetbrains.kotlin.konan.file.File as KFile
-
-private val TestInfo.className: String get() = testClass.orElseGet { fail("Can't get test class name") }.simpleName
-private val TestInfo.methodName: String get() = testMethod.orElseGet { fail("Can't get test method name") }.name
-
-internal fun setUpBuildDir(testInfo: TestInfo): File {
-    val projectBuildDir = System.getenv(ENV_VAR_PROJECT_BUILD_DIR)
-        ?.let { File(it) }
-        ?: fail<Nothing>("$ENV_VAR_PROJECT_BUILD_DIR environment variable not specified")
-
-    assertTrue(projectBuildDir.isDirectory) { "Project build dir does not exist: $projectBuildDir" }
-
-    return projectBuildDir.resolve("t").resolve("${testInfo.className}.${testInfo.methodName}").apply {
-        deleteRecursively()
-        mkdirs()
-    }
-}
-
-internal fun buildLibrary(sourceFile: File, libraryName: String, buildDir: File): File {
-    val configuration = CompilerConfiguration()
-    val environment = createForParallelTests(TestDisposable(), configuration, EnvironmentConfigFiles.JS_CONFIG_FILES)
-
-    configuration.put(CommonConfigurationKeys.MODULE_NAME, libraryName)
-    configuration.put(JSConfigurationKeys.MODULE_KIND, ModuleKind.PLAIN)
-    configuration.put(JSConfigurationKeys.PROPERTY_LAZY_INITIALIZATION, true)
-    configuration.put(JSConfigurationKeys.ZIP_FILE_SYSTEM_ACCESSOR, ZipFileSystemCacheableAccessor(2))
-
-    val psiManager = PsiManager.getInstance(environment.project)
-    val fileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL) as CoreLocalFileSystem
-
-    val virtualFile = fileSystem.findFileByIoFile(sourceFile) ?: error("VirtualFile for $sourceFile not found")
-    val ktFiles = SingleRootFileViewProvider(psiManager, virtualFile).allFiles.filterIsInstance<KtFile>()
-
-    val diagnosticsReporter = DiagnosticReporterFactory.createPendingReporter()
-
-    val jsStdlib = File("libraries/stdlib/js-ir/build/classes/kotlin/js/main").absoluteFile
-    val dependencies = listOf(jsStdlib.absolutePath)
-
-    val moduleStructure = ModulesStructure(
-        project = environment.project,
-        mainModule = MainModule.SourceFiles(ktFiles),
-        compilerConfiguration = configuration,
-        dependencies = dependencies,
-        friendDependenciesPaths = emptyList()
-    )
-
-    val outputStream = ByteArrayOutputStream()
-    val messageCollector = PrintingMessageCollector(PrintStream(outputStream), MessageRenderer.PLAIN_FULL_PATHS, true)
-
-    val analyzedOutput = compileModuleToAnalyzedFirWithPsi(
-        moduleStructure = moduleStructure,
-        ktFiles = ktFiles,
-        libraries = dependencies,
-        friendLibraries = emptyList(),
-        diagnosticsReporter = diagnosticsReporter,
-        incrementalDataProvider = null,
-        lookupTracker = null
-    )
-
-    val fir2IrActualizedResult = transformFirToIr(moduleStructure, analyzedOutput.output, diagnosticsReporter)
-
-    if (analyzedOutput.reportCompilationErrors(moduleStructure, diagnosticsReporter, messageCollector)) {
-        val messages = outputStream.toByteArray().toString(Charset.forName("UTF-8"))
-        fail<Nothing>("The following errors occurred compiling test:\n$messages")
-    }
-
-    val libraryDir = KFile(buildDir.resolve(libraryName).absolutePath)
-    val libraryFile = KFile(libraryDir.absolutePath + ".klib")
-
-    serializeFirKlib(
-        moduleStructure = moduleStructure,
-        firOutputs = analyzedOutput.output,
-        fir2IrActualizedResult = fir2IrActualizedResult,
-        outputKlibPath = libraryDir.absolutePath,
-        messageCollector = messageCollector,
-        diagnosticsReporter = diagnosticsReporter,
-        jsOutputName = libraryName
-    )
-
-    if (messageCollector.hasErrors()) {
-        val messages = outputStream.toByteArray().toString(Charset.forName("UTF-8"))
-        fail<Nothing>("The following errors occurred serializing test klib:\n$messages")
-    }
-
-    libraryDir.zipDirAs(libraryFile)
-    libraryDir.deleteRecursively()
-
-    return File(libraryFile.absolutePath)
-}
-
-@OptIn(ExperimentalLibraryAbiReader::class)
-internal fun patchManifest(libraryFile: File, customManifest: LibraryManifest) {
-    val libraryKFile = KFile(libraryFile.absolutePath)
-    val manifestProperties = resolveSingleFileKlib(libraryKFile).manifestProperties
-
-    fun set(name: String, value: String?) {
-        assertTrue(!value.isNullOrBlank()) { "$name has invalid value: [$value]" }
-        manifestProperties[name] = value!!
-    }
-
-    set(KLIB_PROPERTY_BUILTINS_PLATFORM, customManifest.platform)
-    set(KLIB_PROPERTY_NATIVE_TARGETS, customManifest.nativeTargets.joinToString(" "))
-    set(KLIB_PROPERTY_COMPILER_VERSION, customManifest.compilerVersion)
-    set(KLIB_PROPERTY_ABI_VERSION, customManifest.abiVersion)
-    set(KLIB_PROPERTY_LIBRARY_VERSION, customManifest.libraryVersion)
-    set(KLIB_PROPERTY_IR_PROVIDER, customManifest.irProviderName)
-
-    assertEquals(libraryFile.extension, "klib")
-    val libraryDir = libraryFile.resolveSibling(libraryFile.nameWithoutExtension)
-    val libraryKDir = KFile(libraryDir.absolutePath)
-    libraryKFile.unzipTo(libraryKDir)
-    libraryKFile.deleteRecursively()
-
-    libraryDir.walkTopDown()
-        .filter { it.isFile && it.name == "manifest" }
-        .forEach { manifestProperties.saveToFile(KFile(it.absolutePath)) }
-
-    libraryKDir.zipDirAs(libraryKFile)
-}
-
-private const val ENV_VAR_PROJECT_BUILD_DIR = "PROJECT_BUILD_DIR"