Skip to content

Commit 41ce3e4

Browse files
authored
Merge pull request #8 from afaucogney/well_seperator_rule
Add WellSeparatorDetector rule
2 parents 2af1a97 + 84534a9 commit 41ce3e4

File tree

4 files changed

+287
-0
lines changed

4 files changed

+287
-0
lines changed

Diff for: lint-kit-checks/src/main/java/fr/afaucogney/mobile/android/kit/lint/IssueRegistry.kt

+4
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import com.vanniktech.lintrules.android.ISSUE_WRONG_VIEW_ID_FORMAT
3333
import com.vanniktech.lintrules.android.ISSUE_XML_SPACING
3434
import com.vanniktech.lintrules.rxjava2.ISSUE_DEFAULT_SCHEDULER
3535
import com.vanniktech.lintrules.rxjava2.ISSUE_METHOD_MISSING_CHECK_RETURN_VALUE
36+
import fr.afaucogney.mobile.android.kit.lint.rules.common.WellSeparatorDetector
3637
import fr.afaucogney.mobile.android.kit.lint.rules.contract.NotEnoughtFeatureContractInterfaceSegregationDetector
3738
import fr.afaucogney.mobile.android.kit.lint.rules.contract.ViewModelContractExposeMutableLiveDataDetector
3839
import fr.afaucogney.mobile.android.kit.lint.rules.contract.ViewModelExposedTypeIsNotLiveDataDetector
@@ -81,6 +82,9 @@ class IssueRegistry : IssueRegistry() {
8182
WrongViewTagApiNamingDetector.ISSUE,
8283
NotEnoughtFeatureContractInterfaceSegregationDetector.ISSUE,
8384

85+
// Common
86+
WellSeparatorDetector.ISSUE,
87+
8488
// Architecture
8589

8690
// Android-Lint
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package fr.afaucogney.mobile.android.kit.lint.helper
2+
3+
private const val ALPHA_NUMERIC_REGEX = "[^A-Za-z0-9 ]"
4+
5+
fun String.isUpperCase(): Boolean {
6+
var isUpperCase = true
7+
Regex(ALPHA_NUMERIC_REGEX)
8+
.replace(this, "")
9+
.removeWhitespaces()
10+
.toList()
11+
.forEach { if (!it.isUpperCase()) isUpperCase = false }
12+
return isUpperCase
13+
}
14+
15+
fun String.removeWhitespaces() = replace(" ", "")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package fr.afaucogney.mobile.android.kit.lint.rules.common
2+
3+
import com.android.tools.lint.client.api.UElementHandler
4+
import com.android.tools.lint.detector.api.Category
5+
import com.android.tools.lint.detector.api.Detector
6+
import com.android.tools.lint.detector.api.Implementation
7+
import com.android.tools.lint.detector.api.Issue
8+
import com.android.tools.lint.detector.api.JavaContext
9+
import com.android.tools.lint.detector.api.Scope
10+
import com.android.tools.lint.detector.api.Severity
11+
import fr.afaucogney.mobile.android.kit.lint.helper.isUpperCase
12+
import org.jetbrains.uast.UFile
13+
import java.util.EnumSet
14+
15+
class WellSeparatorDetector : Detector(), Detector.UastScanner {
16+
17+
companion object {
18+
private const val SBC_LINE =
19+
"///////////////////////////////////////////////////////////////////////////"
20+
21+
private val SBC_AUTHORIZED = listOf(
22+
"// CONST",
23+
"// CONFIGURATION",
24+
"// DATA",
25+
"// DEPENDENCY",
26+
"// ERROR CASE",
27+
"// EXCEPTION",
28+
"// FACTORY",
29+
"// FUNCTIONAL CASE",
30+
"// HELPER",
31+
"// INTERFACE",
32+
"// LIFECYCLE",
33+
"// MOCKED DEPENDENCY",
34+
"// PUBLIC API",
35+
"// SPECIALIZATION",
36+
"// SPIED DEPENDENCY",
37+
"// STATE",
38+
"// TECHNICAL CASE",
39+
"// UI SETUP",
40+
"// UNIT UNDER TEST",
41+
"// TAG",
42+
"// VIEW",
43+
)
44+
45+
val ISSUE = Issue.create(
46+
"NotAuthorizedSbcNaming",
47+
"SBC name must be contain in $SBC_AUTHORIZED.",
48+
"Because there are too many SBCs that contain the same thing with different names.",
49+
Category.CORRECTNESS,
50+
4,
51+
Severity.ERROR,
52+
Implementation(
53+
WellSeparatorDetector::class.java,
54+
EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES)
55+
)
56+
)
57+
}
58+
59+
///////////////////////////////////////////////////////////////////////////
60+
// SPECIALIZATION
61+
///////////////////////////////////////////////////////////////////////////
62+
63+
override fun getApplicableUastTypes() = listOf(UFile::class.java)
64+
65+
override fun createUastHandler(context: JavaContext) = RuleHandler(context)
66+
67+
///////////////////////////////////////////////////////////////////////////
68+
// HELPER
69+
///////////////////////////////////////////////////////////////////////////
70+
71+
@SuppressWarnings("TooGenericExceptionCaught", "SwallowedException")
72+
class RuleHandler(private val context: JavaContext) : UElementHandler() {
73+
override fun visitFile(node: UFile) {
74+
node.allCommentsInFile.forEachIndexed { index, comment ->
75+
try {
76+
val currentLine = comment.text
77+
val endLine = node.allCommentsInFile[index + 2].text
78+
if (currentLine == SBC_LINE && endLine == SBC_LINE) {
79+
val nextLine = node.allCommentsInFile[index + 1].text
80+
if (nextLine.isUpperCase() && !SBC_AUTHORIZED.contains(nextLine)) {
81+
context.report(
82+
ISSUE,
83+
node,
84+
context.getNameLocation(node),
85+
StringBuilder()
86+
.append("SBC name not respected")
87+
.appendLine()
88+
.appendLine(currentLine)
89+
.appendLine(nextLine)
90+
.appendLine(endLine)
91+
.toString()
92+
)
93+
}
94+
}
95+
} catch (e: IndexOutOfBoundsException) {
96+
// Do nothing
97+
}
98+
}
99+
}
100+
}
101+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
package fr.afaucogney.mobile.android.kit.lint.rules.common
2+
3+
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
4+
import com.android.tools.lint.checks.infrastructure.TestLintTask
5+
import org.junit.Test
6+
7+
class WellSeparatorDetectorTest {
8+
9+
@Test
10+
fun testSuccessSbc() {
11+
TestLintTask.lint()
12+
.allowMissingSdk()
13+
.files(
14+
LintDetectorTest.kotlin(
15+
"""
16+
|package foo
17+
|
18+
|class Toto {
19+
|
20+
|///////////////////////////////////////////////////////////////////////////
21+
|// PUBLIC API
22+
|///////////////////////////////////////////////////////////////////////////
23+
|
24+
|fun tutu() {}
25+
|
26+
|}""".trimMargin()
27+
)
28+
)
29+
.issues(WellSeparatorDetector.ISSUE)
30+
.run()
31+
.expectClean()
32+
}
33+
34+
@Test
35+
fun testSuccessMultipleSbc() {
36+
TestLintTask.lint()
37+
.allowMissingSdk()
38+
.files(
39+
LintDetectorTest.kotlin(
40+
"""
41+
|package foo
42+
|
43+
|class Toto {
44+
|
45+
|///////////////////////////////////////////////////////////////////////////
46+
|// PUBLIC API
47+
|///////////////////////////////////////////////////////////////////////////
48+
|
49+
|fun tutu() {}
50+
|
51+
|///////////////////////////////////////////////////////////////////////////
52+
|// HELPER
53+
|///////////////////////////////////////////////////////////////////////////
54+
|
55+
|private fun tata() {}
56+
|
57+
|}""".trimMargin()
58+
)
59+
)
60+
.issues(WellSeparatorDetector.ISSUE)
61+
.run()
62+
.expectClean()
63+
}
64+
65+
@Test
66+
fun testFailSbc() {
67+
TestLintTask.lint()
68+
.allowMissingSdk()
69+
.files(
70+
LintDetectorTest.kotlin(
71+
"""
72+
|package foo
73+
|
74+
|class Toto {
75+
|
76+
|///////////////////////////////////////////////////////////////////////////
77+
|// ALL METHODS
78+
|///////////////////////////////////////////////////////////////////////////
79+
|
80+
|fun tutu() {}
81+
|
82+
|}""".trimMargin()
83+
)
84+
)
85+
.issues(WellSeparatorDetector.ISSUE)
86+
.run()
87+
.expectErrorCount(1)
88+
}
89+
90+
@Test
91+
fun testFailSbcWithPlural() {
92+
TestLintTask.lint()
93+
.allowMissingSdk()
94+
.files(
95+
LintDetectorTest.kotlin(
96+
"""
97+
|package foo
98+
|
99+
|class Toto {
100+
|
101+
|///////////////////////////////////////////////////////////////////////////
102+
|// PUBLIC APIS
103+
|///////////////////////////////////////////////////////////////////////////
104+
|
105+
|fun tutu() {}
106+
|
107+
|}""".trimMargin()
108+
)
109+
)
110+
.issues(WellSeparatorDetector.ISSUE)
111+
.run()
112+
.expectErrorCount(1)
113+
}
114+
115+
@Test
116+
fun testComment() {
117+
TestLintTask.lint()
118+
.allowMissingSdk()
119+
.files(
120+
LintDetectorTest.kotlin(
121+
"""
122+
|package foo
123+
|
124+
|class Toto {
125+
|
126+
|// TODO: foo
127+
|
128+
|fun tutu() {}
129+
|
130+
|}""".trimMargin()
131+
)
132+
)
133+
.issues(WellSeparatorDetector.ISSUE)
134+
.run()
135+
.expectClean()
136+
}
137+
138+
@Test
139+
fun testCommentWithSbc() {
140+
TestLintTask.lint()
141+
.allowMissingSdk()
142+
.files(
143+
LintDetectorTest.kotlin(
144+
"""
145+
|package foo
146+
|
147+
|class Toto {
148+
|
149+
|///////////////////////////////////////////////////////////////////////////
150+
|// PUBLIC API
151+
|///////////////////////////////////////////////////////////////////////////`
152+
|
153+
|// TODO: foo
154+
|fun tutu() {}
155+
|
156+
|///////////////////////////////////////////////////////////////////////////
157+
|// HELPER
158+
|///////////////////////////////////////////////////////////////////////////`
159+
|
160+
|}""".trimMargin()
161+
)
162+
)
163+
.issues(WellSeparatorDetector.ISSUE)
164+
.run()
165+
.expectClean()
166+
}
167+
}

0 commit comments

Comments
 (0)