blob: 48745599d294281ceabdfabfa781dc59f97536c8 [file] [log] [blame]
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:Suppress("UnstableApiUsage")
package androidx.navigation.compose.lint
import androidx.compose.lint.test.Stubs
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.checks.infrastructure.TestMode
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
/* ktlint-disable max-line-length */
@RunWith(JUnit4::class)
/**
* Test for [UnrememberedGetBackStackEntryDetector].
*/
class UnrememberedGetBackStackEntryDetectorTest : LintDetectorTest() {
override fun getDetector(): Detector = UnrememberedGetBackStackEntryDetector()
override fun getIssues(): MutableList<Issue> =
mutableListOf(UnrememberedGetBackStackEntryDetector.UnrememberedGetBackStackEntry)
@Test
fun notRemembered() {
lint().files(
kotlin(
"""
package com.example
import androidx.compose.runtime.*
import androidx.navigation.NavController
@Composable
fun Test() {
val navController = NavController()
navController.getBackStackEntry("test")
}
val lambda = @Composable {
val navController = NavController()
navController.getBackStackEntry("test")
}
val lambda2: @Composable () -> Unit = {
val navController = NavController()
navController.getBackStackEntry("test")
}
@Composable
fun LambdaParameter(content: @Composable () -> Unit) {}
@Composable
fun Test2() {
LambdaParameter(content = {
val navController = NavController()
navController.getBackStackEntry("test")
})
LambdaParameter {
val navController = NavController()
navController.getBackStackEntry("test")
}
}
fun test3() {
val localLambda1 = @Composable {
val navController = NavController()
navController.getBackStackEntry("test")
}
val localLambda2: @Composable () -> Unit = {
val navController = NavController()
navController.getBackStackEntry("test")
}
}
@Composable
fun Test4() {
val localObject = object {
val navController = NavController()
val entry = navController.getBackStackEntry("test")
}
}
"""
),
Stubs.Composable,
NAV_CONTROLLER
)
.skipTestModes(TestMode.TYPE_ALIAS)
.run()
.expect(
"""
src/com/example/{.kt:10: Error: Calling getBackStackEntry during composition without using remember with a NavBackStackEntry key [UnrememberedGetBackStackEntry]
navController.getBackStackEntry("test")
~~~~~~~~~~~~~~~~~
src/com/example/{.kt:15: Error: Calling getBackStackEntry during composition without using remember with a NavBackStackEntry key [UnrememberedGetBackStackEntry]
navController.getBackStackEntry("test")
~~~~~~~~~~~~~~~~~
src/com/example/{.kt:20: Error: Calling getBackStackEntry during composition without using remember with a NavBackStackEntry key [UnrememberedGetBackStackEntry]
navController.getBackStackEntry("test")
~~~~~~~~~~~~~~~~~
src/com/example/{.kt:30: Error: Calling getBackStackEntry during composition without using remember with a NavBackStackEntry key [UnrememberedGetBackStackEntry]
navController.getBackStackEntry("test")
~~~~~~~~~~~~~~~~~
src/com/example/{.kt:34: Error: Calling getBackStackEntry during composition without using remember with a NavBackStackEntry key [UnrememberedGetBackStackEntry]
navController.getBackStackEntry("test")
~~~~~~~~~~~~~~~~~
src/com/example/{.kt:41: Error: Calling getBackStackEntry during composition without using remember with a NavBackStackEntry key [UnrememberedGetBackStackEntry]
navController.getBackStackEntry("test")
~~~~~~~~~~~~~~~~~
src/com/example/{.kt:46: Error: Calling getBackStackEntry during composition without using remember with a NavBackStackEntry key [UnrememberedGetBackStackEntry]
navController.getBackStackEntry("test")
~~~~~~~~~~~~~~~~~
src/com/example/{.kt:54: Error: Calling getBackStackEntry during composition without using remember with a NavBackStackEntry key [UnrememberedGetBackStackEntry]
val entry = navController.getBackStackEntry("test")
~~~~~~~~~~~~~~~~~
8 errors, 0 warnings
"""
)
}
@Test
fun rememberedInsideComposableBodyWithoutEntryKey() {
lint().files(
kotlin(
"""
package com.example
import androidx.compose.runtime.*
import androidx.navigation.NavController
@Composable
fun Test() {
val navController = NavController()
val entry = remember { navController.getBackStackEntry("test") }
}
val lambda = @Composable {
val navController = NavController()
val entry = remember { navController.getBackStackEntry("test") }
}
val lambda2: @Composable () -> Unit = {
val navController = NavController()
val entry = remember { navController.getBackStackEntry("test") }
}
@Composable
fun LambdaParameter(content: @Composable () -> Unit) {}
@Composable
fun Test2() {
LambdaParameter(content = {
val navController = NavController()
val entry = remember { navController.getBackStackEntry("test") }
})
LambdaParameter {
val navController = NavController()
val entry = remember { navController.getBackStackEntry("test") }
}
}
fun test3() {
val localLambda1 = @Composable {
val navController = NavController()
val entry = remember { navController.getBackStackEntry("test") }
}
val localLambda2: @Composable () -> Unit = {
val navController = NavController()
val entry = remember { navController.getBackStackEntry("test") }
}
}
"""
),
Stubs.Composable,
Stubs.Remember,
NAV_CONTROLLER,
NAV_BACK_STACK_ENTRY
)
.run()
.expect(
"""
src/com/example/test.kt:10: Error: Calling getBackStackEntry during composition without using remember with a NavBackStackEntry key [UnrememberedGetBackStackEntry]
val entry = remember { navController.getBackStackEntry("test") }
~~~~~~~~~~~~~~~~~
src/com/example/test.kt:15: Error: Calling getBackStackEntry during composition without using remember with a NavBackStackEntry key [UnrememberedGetBackStackEntry]
val entry = remember { navController.getBackStackEntry("test") }
~~~~~~~~~~~~~~~~~
src/com/example/test.kt:20: Error: Calling getBackStackEntry during composition without using remember with a NavBackStackEntry key [UnrememberedGetBackStackEntry]
val entry = remember { navController.getBackStackEntry("test") }
~~~~~~~~~~~~~~~~~
src/com/example/test.kt:30: Error: Calling getBackStackEntry during composition without using remember with a NavBackStackEntry key [UnrememberedGetBackStackEntry]
val entry = remember { navController.getBackStackEntry("test") }
~~~~~~~~~~~~~~~~~
src/com/example/test.kt:34: Error: Calling getBackStackEntry during composition without using remember with a NavBackStackEntry key [UnrememberedGetBackStackEntry]
val entry = remember { navController.getBackStackEntry("test") }
~~~~~~~~~~~~~~~~~
src/com/example/test.kt:41: Error: Calling getBackStackEntry during composition without using remember with a NavBackStackEntry key [UnrememberedGetBackStackEntry]
val entry = remember { navController.getBackStackEntry("test") }
~~~~~~~~~~~~~~~~~
src/com/example/test.kt:46: Error: Calling getBackStackEntry during composition without using remember with a NavBackStackEntry key [UnrememberedGetBackStackEntry]
val entry = remember { navController.getBackStackEntry("test") }
~~~~~~~~~~~~~~~~~
7 errors, 0 warnings
"""
)
}
@Test
fun rememberedInsideComposableBodyWithEntryKey() {
lint().files(
kotlin(
"""
package com.example
import androidx.compose.runtime.*
import androidx.navigation.NavController
import androidx.navigation.NavBackStackEntry
@Composable
fun Test() {
val navController = NavController()
val rememberedEntry = NavBackStackEntry()
val entry = remember(rememberedEntry) { navController.getBackStackEntry("test") }
}
val lambda = @Composable {
val navController = NavController()
val rememberedEntry = NavBackStackEntry()
val entry = remember(rememberedEntry) { navController.getBackStackEntry("test") }
}
val lambda2: @Composable () -> Unit = {
val navController = NavController()
val rememberedEntry = NavBackStackEntry()
val entry = remember(rememberedEntry) { navController.getBackStackEntry("test") }
}
@Composable
fun LambdaParameter(content: @Composable () -> Unit) {}
@Composable
fun Test2() {
LambdaParameter(content = {
val navController = NavController()
val rememberedEntry = NavBackStackEntry()
val entry = remember(rememberedEntry) { navController.getBackStackEntry("test") }
})
LambdaParameter {
val navController = NavController()
val rememberedEntry = NavBackStackEntry()
val entry = remember(rememberedEntry) { navController.getBackStackEntry("test") }
}
}
fun test3() {
val localLambda1 = @Composable {
val navController = NavController()
val rememberedEntry = NavBackStackEntry()
val entry = remember(rememberedEntry) { navController.getBackStackEntry("test") }
}
val localLambda2: @Composable () -> Unit = {
val navController = NavController()
val rememberedEntry = NavBackStackEntry()
val entry = remember(rememberedEntry) { navController.getBackStackEntry("test") }
}
}
"""
),
Stubs.Composable,
Stubs.Remember,
NAV_BACK_STACK_ENTRY,
NAV_CONTROLLER
)
.run()
.expectClean()
}
@Test
fun noErrors() {
lint().files(
kotlin(
"""
package com.example
import androidx.compose.runtime.*
import androidx.navigation.NavController
fun test() {
val navController = NavController()
navController.getBackStackEntry("test")
}
val lambda = {
val navController = NavController()
navController.getBackStackEntry("test")
}
val lambda2: () -> Unit = {
val navController = NavController()
navController.getBackStackEntry("test")
}
fun LambdaParameter(content: () -> Unit) {}
fun test2() {
LambdaParameter(content = {
val navController = NavController()
navController.getBackStackEntry("test")
})
LambdaParameter {
val navController = NavController()
navController.getBackStackEntry("test")
}
}
fun test3() {
val localLambda1 = {
val navController = NavController()
navController.getBackStackEntry("test")
}
val localLambda2: () -> Unit = {
val navController = NavController()
navController.getBackStackEntry("test")
}
}
fun test3() {
class Foo {
val navController = NavController()
val entry = navController.getBackStackEntry("test")
}
val localObject = object {
val navController = NavController()
val entry = navController.getBackStackEntry("test")
}
}
@Composable
fun Test4() {
class Foo {
val navController = NavController()
val entry = navController.getBackStackEntry("test")
}
}
"""
),
Stubs.Composable,
Stubs.Remember,
NAV_CONTROLLER,
NAV_BACK_STACK_ENTRY
)
.run()
.expectClean()
}
}
/* ktlint-enable max-line-length */