From cfb5bc053c38d24a8b132d5569edd3324f5b9b4f Mon Sep 17 00:00:00 2001 From: Saksham Bansal Date: Wed, 14 Feb 2018 18:23:39 +0530 Subject: [PATCH] KotlinLintBear.py: Add bear wrapping ktlint Checks for coding standards or semantic problems in Kotlin files. Closes https://github.com/coala/coala-bears/issues/2152 --- .ci/deps.sh | 5 +++ bears/kotlin/KotlinLintBear.py | 26 +++++++++++++ bears/kotlin/__init__.py | 0 tests/kotlin/KotlinLintBearTest.py | 39 +++++++++++++++++++ tests/kotlin/__init__.py | 0 tests/kotlin/bad_files/bad_import.kt | 3 ++ tests/kotlin/bad_files/bad_modifier_order.kt | 6 +++ tests/kotlin/bad_files/bad_semicolon.kt | 6 +++ .../kotlin/bad_files/bad_string_templates.kt | 2 + tests/kotlin/good_files/good_file.kt | 6 +++ .../kotlin/good_files/good_modifier_order.kt | 6 +++ .../good_files/good_string_templates.kt | 6 +++ tests/kotlin/test_files/.editorconfig | 2 + tests/kotlin/test_files/good_file.kt | 6 +++ 14 files changed, 113 insertions(+) create mode 100644 bears/kotlin/KotlinLintBear.py create mode 100644 bears/kotlin/__init__.py create mode 100644 tests/kotlin/KotlinLintBearTest.py create mode 100644 tests/kotlin/__init__.py create mode 100644 tests/kotlin/bad_files/bad_import.kt create mode 100644 tests/kotlin/bad_files/bad_modifier_order.kt create mode 100644 tests/kotlin/bad_files/bad_semicolon.kt create mode 100644 tests/kotlin/bad_files/bad_string_templates.kt create mode 100644 tests/kotlin/good_files/good_file.kt create mode 100644 tests/kotlin/good_files/good_modifier_order.kt create mode 100644 tests/kotlin/good_files/good_string_templates.kt create mode 100644 tests/kotlin/test_files/.editorconfig create mode 100644 tests/kotlin/test_files/good_file.kt diff --git a/.ci/deps.sh b/.ci/deps.sh index 1ddd006fa8..73dab0524b 100644 --- a/.ci/deps.sh +++ b/.ci/deps.sh @@ -62,3 +62,8 @@ wget "https://downloads.sourceforge.net/project/astyle/astyle/astyle%203.0.1/ast tar -xvzf ~/astyle.tar.gz -C ~/ make -C ~/astyle/build/gcc sudo make install -C ~/astyle/build/gcc + +# ktlint installation +curl -sSLO https://github.com/shyiko/ktlint/releases/download/0.15.0/ktlint +sudo chmod a+x ktlint +sudo mv ktlint /usr/local/bin/ diff --git a/bears/kotlin/KotlinLintBear.py b/bears/kotlin/KotlinLintBear.py new file mode 100644 index 0000000000..dd3ea0b9e4 --- /dev/null +++ b/bears/kotlin/KotlinLintBear.py @@ -0,0 +1,26 @@ +from coalib.bearlib.abstractions.Linter import linter +from dependency_management.requirements.DistributionRequirement import ( + DistributionRequirement) + + +@linter(executable='ktlint', + global_bear=True, + output_format='regex', + output_regex=r'(?P\d+):(?P\d+): ' + r'(?P.+)') +class KotlinLintBear: + """ + Lints your Kotlin files. + Checks for coding standards or semantic problems in Kotlin files. + """ + LANGUAGES = {'kotlin'} + REQUIREMENTS = {DistributionRequirement(brew='shyiko/ktlint/ktlint')} + AUTHORS = {'The coala developers'} + AUTHORS_EMAILS = {'coala-devel@googlegroups.com'} + LICENSE = 'AGPL-3.0' + CAN_DETECT = {'Formatting', 'Syntax'} + SEE_MORE = 'https://ktlint.github.io' + + @staticmethod + def create_arguments(config_file): + return () diff --git a/bears/kotlin/__init__.py b/bears/kotlin/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/kotlin/KotlinLintBearTest.py b/tests/kotlin/KotlinLintBearTest.py new file mode 100644 index 0000000000..fadd6f001f --- /dev/null +++ b/tests/kotlin/KotlinLintBearTest.py @@ -0,0 +1,39 @@ +import os +import unittest +from queue import Queue + +from coalib.settings.Section import Section +from bears.kotlin.KotlinLintBear import KotlinLintBear +from coalib.testing.BearTestHelper import generate_skip_decorator + + +@generate_skip_decorator(KotlinLintBear) +class KotlinLintBearTest(unittest.TestCase): + + def setUp(self): + self.section = Section('Kotlin') + self.queue = Queue() + self.file_dict = {} + self.uut = KotlinLintBear(self.file_dict, self.section, self.queue) + + def set_config_dir(self, directory): + test_path = os.path.abspath(os.path.join( + os.path.dirname(__file__), directory)) + self.uut.get_config_dir = lambda *args, **kwargs: test_path + + def test_bad_files(self): + self.set_config_dir('bad_files') + results = list(self.uut.run_bear_from_section([], {})) + self.assertTrue(len(results) > 10) + + def test_good_files(self): + self.set_config_dir('good_files') + results = list(self.uut.run_bear_from_section([], {})) + self.assertTrue(len(results) == 0) + + def test_config_files(self): + self.set_config_dir('test_files') + results = list(self.uut.run_bear_from_section([], {})) + self.assertTrue(len(results) == 1) + self.assertEqual(results[0].message, + 'File must end with a newline (\\n)') diff --git a/tests/kotlin/__init__.py b/tests/kotlin/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/kotlin/bad_files/bad_import.kt b/tests/kotlin/bad_files/bad_import.kt new file mode 100644 index 0000000000..95e7545308 --- /dev/null +++ b/tests/kotlin/bad_files/bad_import.kt @@ -0,0 +1,3 @@ +import io.vertx.core.* +import com.google.inject.* +import pkg.UnusedClass \ No newline at end of file diff --git a/tests/kotlin/bad_files/bad_modifier_order.kt b/tests/kotlin/bad_files/bad_modifier_order.kt new file mode 100644 index 0000000000..4376a5f7b8 --- /dev/null +++ b/tests/kotlin/bad_files/bad_modifier_order.kt @@ -0,0 +1,6 @@ +abstract internal class A { + open protected val v = "" + open suspend internal fun f(v: Any): Any = "" + lateinit public var lv: String + tailrec abstract fun findFixPoint(x: Double = 1.0): Double +} \ No newline at end of file diff --git a/tests/kotlin/bad_files/bad_semicolon.kt b/tests/kotlin/bad_files/bad_semicolon.kt new file mode 100644 index 0000000000..afe1efc5f7 --- /dev/null +++ b/tests/kotlin/bad_files/bad_semicolon.kt @@ -0,0 +1,6 @@ + package a.b.c; + fun main() { + fun name() { a(); return b } + println(";") + println(); + } \ No newline at end of file diff --git a/tests/kotlin/bad_files/bad_string_templates.kt b/tests/kotlin/bad_files/bad_string_templates.kt new file mode 100644 index 0000000000..81e5b63cb1 --- /dev/null +++ b/tests/kotlin/bad_files/bad_string_templates.kt @@ -0,0 +1,2 @@ +val a = "class = ${String::class.toString()}" +val b = "not ${a}" \ No newline at end of file diff --git a/tests/kotlin/good_files/good_file.kt b/tests/kotlin/good_files/good_file.kt new file mode 100644 index 0000000000..7669a5d7df --- /dev/null +++ b/tests/kotlin/good_files/good_file.kt @@ -0,0 +1,6 @@ +fun a() { + val x = 5 + if (x == 0) { + println(a) + } +} \ No newline at end of file diff --git a/tests/kotlin/good_files/good_modifier_order.kt b/tests/kotlin/good_files/good_modifier_order.kt new file mode 100644 index 0000000000..9b0b52718a --- /dev/null +++ b/tests/kotlin/good_files/good_modifier_order.kt @@ -0,0 +1,6 @@ +internal abstract class A { + protected open val v = "" + internal open suspend fun f(v: Any): Any = "" + public lateinit var lv: String + abstract tailrec fun findFixPoint(x: Double = 1.0): Double +} \ No newline at end of file diff --git a/tests/kotlin/good_files/good_string_templates.kt b/tests/kotlin/good_files/good_string_templates.kt new file mode 100644 index 0000000000..9b0b52718a --- /dev/null +++ b/tests/kotlin/good_files/good_string_templates.kt @@ -0,0 +1,6 @@ +internal abstract class A { + protected open val v = "" + internal open suspend fun f(v: Any): Any = "" + public lateinit var lv: String + abstract tailrec fun findFixPoint(x: Double = 1.0): Double +} \ No newline at end of file diff --git a/tests/kotlin/test_files/.editorconfig b/tests/kotlin/test_files/.editorconfig new file mode 100644 index 0000000000..660b6425a2 --- /dev/null +++ b/tests/kotlin/test_files/.editorconfig @@ -0,0 +1,2 @@ +[*.{kt,kts}] +insert_final_newline=true diff --git a/tests/kotlin/test_files/good_file.kt b/tests/kotlin/test_files/good_file.kt new file mode 100644 index 0000000000..7669a5d7df --- /dev/null +++ b/tests/kotlin/test_files/good_file.kt @@ -0,0 +1,6 @@ +fun a() { + val x = 5 + if (x == 0) { + println(a) + } +} \ No newline at end of file