diff --git a/compose/integrations/composable-test-cases/gradle.properties b/compose/integrations/composable-test-cases/gradle.properties index 3207b3afcf..0adfe994f7 100644 --- a/compose/integrations/composable-test-cases/gradle.properties +++ b/compose/integrations/composable-test-cases/gradle.properties @@ -1,7 +1,7 @@ org.gradle.jvmargs=-Xmx2048M -XX:MaxMetaspaceSize=512m kotlin.code.style=official android.useAndroidX=true -kotlin.version=1.9.21 +kotlin.version=1.9.22 agp.version=7.3.0 compose.version=1.6.0-dev1357 @@ -9,7 +9,7 @@ kotlinx.coroutines.version=1.8.0-RC #empty by default - a default version will be used #compose.kotlinCompilerPluginVersion=23.12.18 -compose.kotlinCompilerPluginVersion=1.5.4 +compose.kotlinCompilerPluginVersion=1.5.8-beta01 # default|failingJs - see enum class CasesToRun tests.casesToRun=default diff --git a/compose/integrations/composable-test-cases/settings.gradle.kts b/compose/integrations/composable-test-cases/settings.gradle.kts index 09806225e6..fdb07a3483 100644 --- a/compose/integrations/composable-test-cases/settings.gradle.kts +++ b/compose/integrations/composable-test-cases/settings.gradle.kts @@ -122,6 +122,9 @@ if (casesToRun.isDefault()) { module(":testcase-expectActual-lib", "testcases/expectActual/lib") module(":testcase-expectActual-main", "testcases/expectActual/main") + + module(":testcase-stability-lib", "testcases/stability/lib") + module(":testcase-stability-main", "testcases/stability/main") } /** diff --git a/compose/integrations/composable-test-cases/testcases/stability/lib/build.gradle.kts b/compose/integrations/composable-test-cases/testcases/stability/lib/build.gradle.kts new file mode 100644 index 0000000000..b96e439ee7 --- /dev/null +++ b/compose/integrations/composable-test-cases/testcases/stability/lib/build.gradle.kts @@ -0,0 +1,20 @@ +plugins { + kotlin("multiplatform") + id("org.jetbrains.compose") +} + +kotlin { + configureTargets() + + sourceSets { + val commonMain by getting { + dependencies { + implementation(compose.runtime) + implementation(getCommonLib()) + } + } + val commonTest by getting { + configureCommonTestDependencies() + } + } +} diff --git a/compose/integrations/composable-test-cases/testcases/stability/lib/src/commonMain/kotlin/Dependencies.kt b/compose/integrations/composable-test-cases/testcases/stability/lib/src/commonMain/kotlin/Dependencies.kt new file mode 100644 index 0000000000..0d3c3bffd5 --- /dev/null +++ b/compose/integrations/composable-test-cases/testcases/stability/lib/src/commonMain/kotlin/Dependencies.kt @@ -0,0 +1,8 @@ +data class UnstableDataClassWithPrivateVar(private var i: Int) { + + fun inc() { i++ } + fun getI() = i +} + + +data class StableDataClassWithPrivateVal(private val i: Int) \ No newline at end of file diff --git a/compose/integrations/composable-test-cases/testcases/stability/main/build.gradle.kts b/compose/integrations/composable-test-cases/testcases/stability/main/build.gradle.kts new file mode 100644 index 0000000000..d49878c7d2 --- /dev/null +++ b/compose/integrations/composable-test-cases/testcases/stability/main/build.gradle.kts @@ -0,0 +1,21 @@ +plugins { + kotlin("multiplatform") + id("org.jetbrains.compose") +} + +kotlin { + configureTargets() + + sourceSets { + val commonMain by getting { + dependencies { + implementation(compose.runtime) + implementation(getCommonLib()) + implementation(getLibDependencyForMain()) + } + } + val commonTest by getting { + configureCommonTestDependencies() + } + } +} diff --git a/compose/integrations/composable-test-cases/testcases/stability/main/src/commonTest/kotlin/Tests.kt b/compose/integrations/composable-test-cases/testcases/stability/main/src/commonTest/kotlin/Tests.kt new file mode 100644 index 0000000000..2a2d54199c --- /dev/null +++ b/compose/integrations/composable-test-cases/testcases/stability/main/src/commonTest/kotlin/Tests.kt @@ -0,0 +1,111 @@ +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import com.example.common.TextLeafNode +import com.example.common.composeText +import kotlinx.coroutines.Job +import kotlinx.coroutines.test.runTest +import kotlin.test.BeforeTest +import kotlin.test.Test +import kotlin.test.assertEquals + +class Tests { + + /** + * Here we use an unstable parameter, and therefore + * we expect the Composable function will NOT skip body execution. + */ + @Test + fun testUnstableParameter() = runTest { + val i = UnstableDataClassWithPrivateVar(0) + val job = Job() + + val state = mutableStateOf(0) + val root = composeText(coroutineContext + job) { + UseUnstableDataClassInstance(i) + TextLeafNode("state=" + state.value.toString()) + } + + assertEquals("root:{UnstableDataClassWithPrivateVar(i=0), state=0}", root.dump()) + assertEquals(1, i.getI()) + state.value += 1 + + testScheduler.advanceUntilIdle() + assertEquals("root:{UnstableDataClassWithPrivateVar(i=1), state=1}", root.dump()) + assertEquals(2, i.getI()) + } + + @Test + fun testUnstableParameterOfLocalType() = runTest { + val i = LocalUnstableDataClassWithPrivateVar(0) + val job = Job() + + val state = mutableStateOf(0) + val root = composeText(coroutineContext + job) { + UseLocalUnstableDataClassWithPrivateVar(i) + TextLeafNode("state=" + state.value.toString()) + } + + assertEquals("root:{LocalUnstableDataClassWithPrivateVar(i=0), state=0}", root.dump()) + assertEquals(1, i.getI()) + state.value += 1 + + testScheduler.advanceUntilIdle() + assertEquals("root:{LocalUnstableDataClassWithPrivateVar(i=1), state=1}", root.dump()) + assertEquals(2, i.getI()) + } + + @Test + fun testStableParameter() = runTest { + val i = StableDataClassWithPrivateVal(0) + val job = Job() + + val state = mutableStateOf(0) + val root = composeText(coroutineContext + job) { + UseStableDataClassWithPrivateVar(i) + TextLeafNode("state=" + state.value.toString()) + } + + assertEquals("root:{StableDataClassWithPrivateVal(i=0), counter=0, state=0}", root.dump()) + assertEquals(1, counter) + + state.value += 1 + testScheduler.advanceUntilIdle() + assertEquals("root:{StableDataClassWithPrivateVal(i=0), counter=0, state=1}", root.dump()) + assertEquals(1, counter) + } + + @BeforeTest + fun before() { + counter = 0 + } +} + +private var counter = 0 + +@Composable +fun UseUnstableDataClassInstance(i: UnstableDataClassWithPrivateVar) { + TextLeafNode(i.toString()) + i.inc() +} + +@Composable +fun UseStableDataClassWithPrivateVar(i: StableDataClassWithPrivateVal) { + TextLeafNode(i.toString()) + TextLeafNode("counter=$counter") + counter++ +} + + +/** + * Same as [UnstableDataClassWithPrivateVar] but defined in the same module that a function which uses it + */ +data class LocalUnstableDataClassWithPrivateVar(private var i: Int) { + fun inc() { i++ } + fun getI() = i +} + +@Composable +fun UseLocalUnstableDataClassWithPrivateVar(i: LocalUnstableDataClassWithPrivateVar) { + TextLeafNode(i.toString()) + i.inc() +} \ No newline at end of file