Search code examples
macosgradlekotlin-multiplatformkotlin-native

Running tests from gradle in pure Kotlin Native on a Mac


When using Kotlin Native/Multiplatform I cannot get it to run tests without introducing Java/JUnit into my build.gradle.kts. If I don't do that it seems to simply conclude that my tests tasks are not enabled:

> Task :nativeTest SKIPPED
Skipping task ':nativeTest' as task onlyIf is false.
:nativeTest (Thread[Execution worker for ':',5,main]) completed. Took 0.0 secs.
:allTests (Thread[Execution worker for ':',5,main]) started.

> Task :allTests
Caching disabled for task ':allTests' because:
  Build cache is disabled
Task ':allTests' is not up-to-date because:
  Output property 'destinationDirectory' file /Users/rohde/git/deleteme/build/reports/tests/allTests has been removed.
:allTests - no binary test results found in dirs: [/Users/rohde/git/deleteme/build/test-results/nativeTest/binary].
:allTests (Thread[Execution worker for ':',5,main]) completed. Took 0.005 secs.
:check (Thread[Execution worker for ':',5,main]) started.

> Task :check
Skipping task ':check' as it has no actions.
:check (Thread[Execution worker for ':',5,main]) completed. Took 0.0 secs.
producer locations for task group 1 (Thread[Execution worker for ':',5,main]) started.
producer locations for task group 1 (Thread[Execution worker for ':',5,main]) completed. Took 0.0 secs.

This is run with the following (trimmed) gradle configuration:

plugins {
    kotlin("multiplatform") version "1.8.20"
}

// ...

kotlin {
    val hostOs = System.getProperty("os.name")
    val isMingwX64 = hostOs.startsWith("Windows")
    val nativeTarget = when {
            hostOs == "Mac OS X" -> macosX64("native")
            hostOs == "Linux" -> linuxX64("native")
            isMingwX64 -> mingwX64("native")
            else -> throw GradleException("Host OS is not supported in Kotlin/Native.")
    }

    sourceSets {
        val commonMain by getting
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test"))
            }
        }
    }
}

The below strikethrough text is kept for history, but turns out to be a false positive

Now if I in the `kotlin` block add:
        jvm {
            testRuns["test"].executionTask.configure {
                useJUnitPlatform()
            }
        }

it does work, however it also configures the jvm dependencies which means I need to supply implementations for the expect cases, which I (at least at the current time) do now want for the JVM

After a lot of searching, I haven't gotten any understanding of how to deal with the various onlyIf conditions I've seen fail

How do I enable tests for a Kotlin Native project without introducing all the JVM dependencies? It's fine if it's only in gradle (could I for instance introduce the useJUnitPlatform without adding the source dependencies in my project?)


Solution

  • After help from ephemient on the Kotlin Slack channel (thanks, ephemient!) I uncovered the following

    The problem arises because the Mac I'm using is running on a M1 CPU, i.e. it's a macosArm64 and not a macosX64 as in the gradle setup

    Thus changing:

    // hostOs == "Mac OS X" -> macosX64("native")
    hostOs == "Mac OS X" -> macosArm64("native")
    

    is all that what is needed

    An improved way of doing it is using the newer way of specifying the targets, resulting in the following:

    @OptIn(ExperimentalKotlinGradlePluginApi::class)
    kotlin {
        targetHierarchy.default()
    
        linuxX64()
        macosX64()
        macosArm64()
        // ... etc for whatever targets desired
    }
    

    Whatever triggered the false positive on the JVM setup I cannot tell, and of course I cannot reproduce