/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.fenix.detektrules import io.gitlab.arturbosch.detekt.api.CodeSmell import io.gitlab.arturbosch.detekt.api.Config import io.gitlab.arturbosch.detekt.api.Debt import io.gitlab.arturbosch.detekt.api.Entity import io.gitlab.arturbosch.detekt.api.Issue import io.gitlab.arturbosch.detekt.api.Rule import io.gitlab.arturbosch.detekt.api.Severity import io.gitlab.arturbosch.detekt.api.internal.PathFilters import org.jetbrains.kotlin.psi.KtAnnotationEntry private val BANNED_TEST_RUNNERS = setOf( // When updating this list, also update the violation message. "AndroidJUnit4", "RobolectricTestRunner", ) // There is a change to how we output violations in a different PR so the formatting for message // might be weird but it should still be readable. private val VIOLATION_MSG = """The following code blocks: | | @RunWith(AndroidJUnit4::class) | @Config(application = TestApplication::class) | OR | @RunWith(RobolectricTestRunner::class) | @Config(application = TestApplication::class) | | should be replaced with: | | @RunWith(FenixRobolectricTestRunner::class) | | To reduce redundancy of setting @Config. No @Config specification is necessary because | the FenixRobolectricTestRunner sets it automatically. | | Relatedly, adding robolectric to a test increases its runtime non-trivially so please | ensure Robolectric is necessary before adding it.""".trimMargin() /** * Ensures we're using the correct Robolectric unit test runner. */ class MozillaCorrectUnitTestRunner(config: Config) : Rule(config) { override val issue = Issue( MozillaCorrectUnitTestRunner::class.simpleName!!, Severity.Defect, "Verifies we're using the correct Robolectric unit test runner", Debt.FIVE_MINS, ) override val filters: PathFilters? get() = PathFilters.of( includes = listOf("**/test/**"), // unit tests only. excludes = emptyList(), ) override fun visitAnnotationEntry(annotationEntry: KtAnnotationEntry) { super.visitAnnotationEntry(annotationEntry) // Example of an annotation: @RunWith(FenixRobolectricUnitTestRunner::class) val annotationClassName = annotationEntry.shortName?.identifier if (annotationClassName == "RunWith") { // Example arg in parens: "(FenixRobolectricUnitTestRunner::class)" val argInParens = annotationEntry.lastChild.node.chars val argClassName = argInParens.substring(1 until argInParens.indexOf(":")) val isInViolation = BANNED_TEST_RUNNERS.any { it == argClassName } if (isInViolation) { report(CodeSmell(issue, Entity.from(annotationEntry), VIOLATION_MSG)) } } } }