diff --git a/kotlin-native/Interop/Indexer/src/test/kotlin/org/jetbrains/kotlin/native/interop/indexer/ModuleTests.kt b/kotlin-native/Interop/Indexer/src/test/kotlin/org/jetbrains/kotlin/native/interop/indexer/ModuleTests.kt new file mode 100644 index 00000000000..8d0370de5bf --- /dev/null +++ b/kotlin-native/Interop/Indexer/src/test/kotlin/org/jetbrains/kotlin/native/interop/indexer/ModuleTests.kt @@ -0,0 +1,166 @@ +/* + * Copyright 2010-2021 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.native.interop.indexer + +import java.io.File +import kotlin.test.Test +import kotlin.test.assertContains +import kotlin.test.assertEquals +import kotlin.test.assertFails + +// Note: this class contains only very basic tests. +class ModuleTests : IndexerTests() { + + @Test + fun testSingleHeaderModule() { + val files = TempFiles("testSingleHeaderModule") + + val header = files.file("Foo.h", "") + + files.file("module.modulemap", """ + module Foo { + header "Foo.h" + } + """.trimIndent()) + + val modulesInfo = getModulesInfo(compilationIncluding(files.directory), listOf("Foo")) + assertEquals(setOf(header.absolutePath), modulesInfo.ownHeaders) + assertEquals(listOf(header.absolutePath), modulesInfo.topLevelHeaders.canonicalize()) + } + + @Test + fun testModuleWithTransitiveInclude() { + val files = TempFiles("testModuleWithTransitiveInclude") + + val fooH = files.file("Foo.h", """ + #include "Bar.h" + """.trimIndent()) + + val barH = files.file("Bar.h", "") + + files.file("module.modulemap", """ + module Foo { + header "Foo.h" + } + """.trimIndent()) + + val modulesInfo = getModulesInfo(compilationIncluding(files.directory), listOf("Foo")) + assertEquals(setOf(fooH.absolutePath, barH.absolutePath), modulesInfo.ownHeaders) + assertEquals(listOf(fooH.absolutePath), modulesInfo.topLevelHeaders.canonicalize()) + } + + @Test + fun testModuleImportingOtherModule() { + val files = TempFiles("testModuleImportingOtherModule") + + val fooH = files.file("Foo.h", """ + #include "Bar.h" + """.trimIndent()) + + files.file("Bar.h", "") + + files.file("module.modulemap", """ + module Foo { + header "Foo.h" + } + module Bar { + header "Bar.h" + } + """.trimIndent()) + + val modulesInfo = getModulesInfo(compilationIncluding(files.directory), listOf("Foo")) + assertEquals(setOf(fooH.absolutePath), modulesInfo.ownHeaders) + assertEquals(listOf(fooH.absolutePath), modulesInfo.topLevelHeaders.canonicalize()) + } + + @Test + fun testFrameworkModule() { + val files = TempFiles("testFramework") + val fooH = files.file("Foo.framework/Headers/Foo.h", """ + #include "Bar.h" + #include + """.trimIndent()) + + val barH = files.file("Foo.framework/Headers/Bar.h", "") + val bazH = files.file("Foo.framework/Headers/Baz.h", "") + + files.file("Foo.framework/Modules/module.modulemap", """ + framework module Foo { + umbrella header "Foo.h" + } + """.trimIndent()) + + val modulesInfo = getModulesInfo(compilation("-F${files.directory}"), listOf("Foo")) + assertEquals(setOf(fooH.absolutePath, barH.absolutePath, bazH.absolutePath), modulesInfo.ownHeaders) + assertEquals(listOf(fooH.absolutePath), modulesInfo.topLevelHeaders.canonicalize()) + } + + @Test + fun testMissingModule() { + val files = TempFiles("testMissingModule") + + val compilation = compilationIncluding(files.directory) + + val error = assertFails { + getModulesInfo(compilation, modules = listOf("Foo")) + } + + assertContains(error.message.orEmpty(), "fatal error: module 'Foo' not found") + } + + @Test + fun testModuleWithMissingHeader() { + val files = TempFiles("testModuleWithMissingHeader") + + files.file("module.modulemap", """ + module Foo { + header "Foo.h" + } + """.trimIndent()) + + val compilation = compilationIncluding(files.directory) + + val error = assertFails { + getModulesInfo(compilation, modules = listOf("Foo")) + } + + assertContains(error.message.orEmpty(), "fatal error: could not build module 'Foo'") + } + + @Test + fun testModuleWithBadCode() { + val files = TempFiles("testModuleWithBadCode") + + files.file("Foo.h", """ + bad code; + """.trimIndent()) + + files.file("module.modulemap", """ + module Foo { + header "Foo.h" + } + """.trimIndent()) + + val compilation = compilationIncluding(files.directory) + + val error = assertFails { + getModulesInfo(compilation, modules = listOf("Foo")) + } + + assertContains(error.message.orEmpty(), "fatal error: could not build module 'Foo'") + } + + private fun List.canonicalize(): List = this.map { File(it).canonicalPath } + + private fun compilationIncluding(includeDirectory: File) = compilation("-I$includeDirectory") + + private fun compilation(vararg args: String) = CompilationImpl( + includes = emptyList(), + additionalPreambleLines = emptyList(), + compilerArgs = listOf(*args), + language = Language.OBJECTIVE_C + ) +}