diff options
3 files changed, 184 insertions, 5 deletions
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DoNotDirectlyConstructKosmosDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DoNotDirectlyConstructKosmosDetector.kt new file mode 100644 index 000000000000..40fac0d05b96 --- /dev/null +++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DoNotDirectlyConstructKosmosDetector.kt @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2023 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. + */ + +package com.android.internal.systemui.lint + +import com.android.tools.lint.detector.api.Category +import com.android.tools.lint.detector.api.Detector +import com.android.tools.lint.detector.api.Implementation +import com.android.tools.lint.detector.api.Issue +import com.android.tools.lint.detector.api.JavaContext +import com.android.tools.lint.detector.api.Scope +import com.android.tools.lint.detector.api.Severity +import com.android.tools.lint.detector.api.SourceCodeScanner +import com.intellij.psi.PsiMethod +import org.jetbrains.uast.UCallExpression +import org.jetbrains.uast.getContainingUClass + +/** + * Detects direct construction of `Kosmos()` in subclasses of SysuiTestCase, which can and should + * use `testKosmos`. See go/thetiger + */ +class DoNotDirectlyConstructKosmosDetector : Detector(), SourceCodeScanner { + override fun getApplicableConstructorTypes() = listOf("com.android.systemui.kosmos.Kosmos") + + override fun visitConstructor( + context: JavaContext, + node: UCallExpression, + constructor: PsiMethod, + ) { + val superClassNames = + node.getContainingUClass()?.superTypes.orEmpty().map { it.resolve()?.qualifiedName } + if (superClassNames.contains("com.android.systemui.SysuiTestCase")) { + context.report( + issue = ISSUE, + scope = node, + location = context.getLocation(node.methodIdentifier), + message = "Prefer testKosmos to direct Kosmos() in sysui tests. go/testkosmos", + ) + } + super.visitConstructor(context, node, constructor) + } + + companion object { + @JvmStatic + val ISSUE = + Issue.create( + id = "DoNotDirectlyConstructKosmos", + briefDescription = + "Prefer testKosmos to direct Kosmos() in sysui tests. go/testkosmos", + explanation = + """ + SysuiTestCase.testKosmos allows us to pre-populate a Kosmos instance with + team-standard fixture values, and makes it easier to make centralized changes + when necessary. See go/testkosmos + """, + category = Category.TESTING, + priority = 8, + severity = Severity.WARNING, + implementation = + Implementation( + DoNotDirectlyConstructKosmosDetector::class.java, + Scope.JAVA_FILE_SCOPE, + ), + ) + } +} diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/RunTestShouldUseKosmosDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/RunTestShouldUseKosmosDetector.kt index 4927fb9dc67d..13ffa6c5deaa 100644 --- a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/RunTestShouldUseKosmosDetector.kt +++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/RunTestShouldUseKosmosDetector.kt @@ -29,16 +29,12 @@ import com.intellij.psi.PsiMethod import org.jetbrains.uast.UCallExpression import org.jetbrains.uast.getContainingUFile -/** - * Detects test function naming violations regarding use of the backtick-wrapped space-allowed - * feature of Kotlin functions. - */ +/** Detects use of `TestScope.runTest` when we should use `Kosmos.runTest` by go/kosmos-runtest */ class RunTestShouldUseKosmosDetector : Detector(), SourceCodeScanner { override fun getApplicableMethodNames() = listOf("runTest") override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) { if (method.getReceiver()?.qualifiedName == "kotlinx.coroutines.test.TestScope") { - val imports = node.getContainingUFile()?.imports.orEmpty().mapNotNull { it.importReference?.asSourceString() diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DoNotDirectlyConstructKosmosTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DoNotDirectlyConstructKosmosTest.kt new file mode 100644 index 000000000000..20f6bcbdbbfe --- /dev/null +++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DoNotDirectlyConstructKosmosTest.kt @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2023 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. + * + */ + +package com.android.internal.systemui.lint + +import com.android.tools.lint.checks.infrastructure.TestFile +import com.android.tools.lint.checks.infrastructure.TestFiles +import com.android.tools.lint.checks.infrastructure.TestLintResult +import com.android.tools.lint.detector.api.Detector +import com.android.tools.lint.detector.api.Issue +import org.junit.Test + +class DoNotDirectlyConstructKosmosTest : SystemUILintDetectorTest() { + override fun getDetector(): Detector = DoNotDirectlyConstructKosmosDetector() + + override fun getIssues(): List<Issue> = listOf(DoNotDirectlyConstructKosmosDetector.ISSUE) + + @Test + fun wronglyTriesToDirectlyConstructKosmos() { + val runOnSource = + runOnSource( + """ + package test.pkg.name + + import com.android.systemui.kosmos.Kosmos + import com.android.systemui.SysuiTestCase + + class MyTest: SysuiTestCase { + val kosmos = Kosmos() + } + """ + ) + + runOnSource + .expectWarningCount(1) + .expect( + """ + src/test/pkg/name/MyTest.kt:7: Warning: Prefer testKosmos to direct Kosmos() in sysui tests. go/testkosmos [DoNotDirectlyConstructKosmos] + val kosmos = Kosmos() + ~~~~~~ + 0 errors, 1 warnings + """ + ) + } + + @Test + fun okToConstructKosmosIfNotInSysuiTestCase() { + val runOnSource = + runOnSource( + """ + package test.pkg.name + + import com.android.systemui.kosmos.Kosmos + + class MyTest { + val kosmos = Kosmos() + } + """ + ) + + runOnSource.expectWarningCount(0) + } + + private fun runOnSource(source: String): TestLintResult { + return lint() + .files(TestFiles.kotlin(source).indented(), kosmosStub, sysuiTestCaseStub) + .issues(DoNotDirectlyConstructKosmosDetector.ISSUE) + .run() + } + + companion object { + private val kosmosStub: TestFile = + kotlin( + """ + package com.android.systemui.kosmos + + class Kosmos + """ + ) + + private val sysuiTestCaseStub: TestFile = + kotlin( + """ + package com.android.systemui + + class SysuiTestCase + """ + ) + } +} |