[K/N][cinterop] Indexer unit-tests of objcClassesIncludingCategories

This commit is contained in:
Sergey Bogolepov
2023-01-12 13:08:57 +02:00
committed by Space Team
parent eded880225
commit 898dd02d29
7 changed files with 160 additions and 2 deletions
@@ -0,0 +1,74 @@
/*
* 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.native.interop.gen
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.native.interop.indexer.IndexerResult
import org.junit.Assume
import kotlin.test.*
// Note: A better place for these tests would be Indexer module.
// But infrastructure that is required for these tests belongs to StubGenerator.
class IncludeCategoriesTests : InteropTestsBase() {
private fun IndexerResult.getObjCClass(name: String) =
index.objCClasses.first { it.name == name }
private fun IndexerResult.getObjCCategory(name: String) =
index.objCCategories.first { it.name == name }
@BeforeTest
fun checkPlatform() {
Assume.assumeTrue(HostManager.hostIsMac)
}
@Test
fun `smoke 0`() {
val index = buildNativeIndex("IncludeCategories", "includeCategory0.def")
val myClass = index.getObjCClass("MyClass")
val myClassCategories = myClass.includedCategories.map { it.name }
assertContains(myClassCategories, "IncludeCategory")
assertContains(myClassCategories, "IncludeCategory2")
}
@Test
fun `only specific classes include categories`() {
val index = buildNativeIndex("IncludeCategories", "includeCategory0.def")
val skipClass = index.getObjCClass("SkipClass")
assertTrue(skipClass.includedCategories.isEmpty())
}
@Test
fun `category from another header is not included`() {
val index = buildNativeIndex("IncludeCategories", "includeCategory0.def")
val myClass = index.getObjCClass("MyClass")
val myClassCategories = myClass.includedCategories.map { it.name }
assertContains(myClassCategories, "IncludeCategory")
assertFalse("SkipCategory" in myClassCategories)
}
@Test
fun `external category is not included into index`() {
val dependencyIndex = buildNativeIndex("IncludeCategories", "includeCategory0.def")
val index = buildNativeIndex("IncludeCategories", "includeCategory1.def", mockImports(dependencyIndex))
val derivedClass = index.getObjCClass("Derived")
val myClass = derivedClass.baseClass!!
assertEquals("MyClass", myClass.name)
assertFalse(myClass in index.index.objCClasses)
val myClassCategories = myClass.includedCategories
assertTrue(myClassCategories.isNotEmpty())
assertTrue(myClassCategories.all { it !in index.index.objCCategories })
}
@Test
fun `category is not included into dependency class`() {
val dependencyIndex = buildNativeIndex("IncludeCategories", "includeCategory0.def")
val index = buildNativeIndex("IncludeCategories", "includeCategory2.def", mockImports(dependencyIndex))
val category = index.getObjCCategory("ChildCategory")
assertFalse(category in category.clazz.includedCategories)
}
}
@@ -12,10 +12,14 @@ import org.jetbrains.kotlin.konan.util.NativeMemoryAllocator
import org.jetbrains.kotlin.native.interop.gen.jvm.KotlinPlatform
import org.jetbrains.kotlin.native.interop.gen.jvm.buildNativeLibrary
import org.jetbrains.kotlin.native.interop.gen.jvm.prepareTool
import org.jetbrains.kotlin.native.interop.indexer.HeaderId
import org.jetbrains.kotlin.native.interop.indexer.IndexerResult
import org.jetbrains.kotlin.native.interop.indexer.Location
import org.jetbrains.kotlin.native.interop.indexer.NativeLibrary
import org.jetbrains.kotlin.native.interop.tool.CInteropArguments
import kotlin.test.*
import java.io.File
import java.nio.file.Paths
abstract class InteropTestsBase {
init {
@@ -47,7 +51,7 @@ abstract class InteropTestsBase {
}
}
protected fun buildNativeLibraryFrom(defFile: File, headersDirectory: File): NativeLibrary {
protected fun buildNativeLibraryFrom(defFile: File, headersDirectory: File, imports: Imports = ImportsMock()): NativeLibrary {
val tool = prepareTool(HostManager.hostName, KotlinPlatform.NATIVE, runFromDaemon = true)
val cinteropArguments = CInteropArguments()
cinteropArguments.argParser.parse(arrayOf(
@@ -57,7 +61,40 @@ abstract class InteropTestsBase {
tool,
DefFile(defFile, tool.substitutions),
cinteropArguments,
ImportsImpl(emptyMap())
imports
)
}
protected fun getTestResources(directoryName: String): File {
val resource = this::class.java.getResource("/$directoryName")
return Paths.get(resource.toURI()).toFile()
}
protected fun buildNativeLibraryFrom(directoryName: String, defFileName: String, imports: Imports = ImportsMock()): NativeLibrary {
val directory = getTestResources(directoryName)
val defFile = File(directory, defFileName)
return buildNativeLibraryFrom(defFile, directory, imports)
}
protected fun buildNativeIndex(directoryName: String, defFileName: String, imports: Imports = ImportsMock()): IndexerResult {
val library = buildNativeLibraryFrom(directoryName, defFileName, imports)
return org.jetbrains.kotlin.native.interop.indexer.buildNativeIndex(library, verbose = false)
}
protected fun mockImports(dependencyIndex: IndexerResult, packageName: String = "dependencyLibrary"): Imports {
return ImportsMock(dependencyIndex.index.includedHeaders.associateWith { packageName })
}
/**
* Trivial implementation of [Imports] interface, untied from KonanLibrary.
*/
protected class ImportsMock(private val headerToPackage: Map<HeaderId, String> = emptyMap()) : Imports {
override fun getPackage(location: Location): String? {
return headerToPackage[location.headerId]
}
override fun isImported(headerId: HeaderId): Boolean {
return headerId in headerToPackage
}
}
}
@@ -0,0 +1,19 @@
#ifndef _HEADER1_
#define _HEADER1_
@interface MyClass
@end
@interface MyClass(IncludeCategory)
@end
@interface MyClass(IncludeCategory2)
@end
@interface SkipClass
@end
@interface SkipClass(IncludeCategory)
@end
#endif
@@ -0,0 +1,10 @@
#ifndef _HEADER2_
#define _HEADER2_
#include "header1.h"
@interface MyClass(SkipCategory)
- (void)skipMethod;
@end
#endif
@@ -0,0 +1,4 @@
language = Objective-C
headers = header1.h header2.h
objcClassesIncludingCategories = MyClass
@@ -0,0 +1,7 @@
language = Objective-C
objcClassesIncludingCategories = MyClass
---
#include <header1.h>
@interface Derived : MyClass
@end
@@ -0,0 +1,7 @@
language = Objective-C
objcClassesIncludingCategories = MyClass
---
#include <header1.h>
@interface MyClass(ChildCategory)
@end