Skip to content

Commit

Permalink
Fixed smoke tests (#1769)
Browse files Browse the repository at this point in the history
  • Loading branch information
nulls authored Nov 7, 2023
1 parent c1c3cab commit d981125
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 55 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/**
* Copied from KtLint and open the constructor
*/

@file:Suppress(
"TOO_LONG_FUNCTION",
"PACKAGE_NAME_INCORRECT_PREFIX",
"PACKAGE_NAME_INCORRECT_PATH",
"KDOC_NO_CONSTRUCTOR_PROPERTY",
"MISSING_KDOC_CLASS_ELEMENTS",
"MISSING_KDOC_ON_FUNCTION",
"KDOC_WITHOUT_PARAM_TAG",
"KDOC_WITHOUT_RETURN_TAG",
)

package com.pinterest.ktlint.rule.engine.api

import com.pinterest.ktlint.rule.engine.api.KtLintRuleEngine.Companion.STDIN_FILE
import org.jetbrains.kotlin.konan.file.file
import java.io.File
import java.nio.file.Path
import kotlin.io.path.pathString

/**
* A representation of a block of code. Use one of the factory methods [fromFile], [fromPath], [fromSnippet] or [fromStdin] to instantiate.
*/
public class Code(
public val content: String,
public val fileName: String?,
public val filePath: Path?,
public val script: Boolean,
public val isStdIn: Boolean,
) {
public fun fileNameOrStdin(): String =
if (isStdIn) {
STDIN_FILE
} else {
fileName.orEmpty()
}

public fun filePathOrStdin(): String =
if (isStdIn) {
STDIN_FILE
} else {
filePath?.pathString.orEmpty()
}

public companion object {
/**
* Create [Code] from a [file] containing valid Kotlin code or script. The '.editorconfig' files on the path to [file] are taken
* into account.
*/
public fun fromFile(file: File): Code =
Code(
content = file.readText(),
fileName = file.name,
filePath = file.toPath(),
script = file.name.endsWith(".kts", ignoreCase = true),
isStdIn = false,
)

/**
* Create [Code] from a [path] to a file containing valid Kotlin code or script. The '.editorconfig' files on the path to [file] are
* taken into account. This method is intended to be used in unit tests. In order to work with the Ktlint test file system it needs
* to make additional call to get the file system which makes it slower compared to [fromFile]. Prefer to use [fromFile].
*/
public fun fromPath(path: Path): Code {
// Resolve the file based on the file system of the original path given.
val file =
path
.fileSystem
.file(path.pathString)
return Code(
content = file.readStrings().joinToString(separator = "\n"),
fileName = file.name,
filePath = path,
script = file.name.endsWith(".kts", ignoreCase = true),
isStdIn = false,
)
}

/**
* The [content] represent a valid piece of Kotlin code or Kotlin script. The '.editorconfig' files on the filesystem are ignored as
* the snippet is not associated with a file path. Use [Code.fromFile] for scanning a file while at the same time respecting the
* '.editorconfig' files on the path to the file.
*/
public fun fromSnippet(
content: String,
script: Boolean = false,
): Code =
Code(
content = content,
filePath = null,
fileName = null,
script = script,
isStdIn = true,
)

/**
* Create [Code] by reading the snippet from 'stdin'. No '.editorconfig' are taken into account. The '.editorconfig' files on the
* filesystem are ignored as the snippet is not associated with a file path. Use [Code.fromFile] for scanning a file while at the
* same time respecting the '.editorconfig' files on the path to the file.
*/
public fun fromStdin(): Code = fromSnippet(String(System.`in`.readBytes()))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import com.pinterest.ktlint.rule.engine.api.KtLintRuleEngine
import com.pinterest.ktlint.rule.engine.api.LintError
import java.nio.file.Path

private typealias FormatCallback = (LintError, Boolean) -> Unit
private typealias LintCallback = (LintError) -> Unit

/**
Expand All @@ -23,12 +22,12 @@ class DiktatProcessorFactoryImpl : DiktatProcessorFactory {
override fun fix(
file: Path,
callback: DiktatCallback,
): String = ktLintRuleEngine.format(file.toKtLint(), callback.toKtLintForFormat())
): String = ktLintRuleEngine.formatSilentlyThenLint(file.toKtLint(), callback.toKtLintForLint())
override fun fix(
code: String,
isScript: Boolean,
callback: DiktatCallback
): String = ktLintRuleEngine.format(code.toKtLint(isScript), callback.toKtLintForFormat())
): String = ktLintRuleEngine.formatSilentlyThenLint(code.toKtLint(isScript), callback.toKtLintForLint())
override fun check(
file: Path,
callback: DiktatCallback,
Expand All @@ -48,12 +47,26 @@ class DiktatProcessorFactoryImpl : DiktatProcessorFactory {

private fun String.toKtLint(isScript: Boolean): Code = Code.fromSnippet(this, isScript)

private fun DiktatCallback.toKtLintForFormat(): FormatCallback = { error, isCorrected ->
this(error.wrap(), isCorrected)
}

private fun DiktatCallback.toKtLintForLint(): LintCallback = { error ->
this(error.wrap(), false)
}

private fun KtLintRuleEngine.formatSilentlyThenLint(
code: Code,
callback: LintCallback,
): String {
val formatResult = format(code)
lint(
code = Code(
content = formatResult,
fileName = code.fileName,
filePath = code.filePath,
script = code.script,
isStdIn = code.isStdIn,
),
callback = callback,
)
return formatResult
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ import com.saveourtool.diktat.util.isKotlinScript
import io.github.oshai.kotlinlogging.KotlinLogging
import org.jetbrains.kotlin.KtNodeTypes.DOT_QUALIFIED_EXPRESSION
import org.jetbrains.kotlin.KtNodeTypes.FILE_ANNOTATION_LIST
import org.jetbrains.kotlin.KtNodeTypes.IMPORT_LIST
import org.jetbrains.kotlin.KtNodeTypes.PACKAGE_DIRECTIVE
import org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION
import org.jetbrains.kotlin.com.intellij.lang.ASTFactory
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl
Expand Down Expand Up @@ -260,12 +262,23 @@ class PackageNaming(configRules: List<RulesConfig>) : DiktatRule(
} else {
packageDirectiveParent.replaceChild(packageDirectiveNode, newPackageDirective)
}
if (newPackageDirective.treeNext.elementType != WHITE_SPACE) {
packageDirectiveParent.addChild(PsiWhiteSpaceImpl("\n"), newPackageDirective.treeNext)
}
addWhiteSpaceIfRequired(newPackageDirective, packageDirectiveParent)
}
}

private fun addWhiteSpaceIfRequired(packageNode: ASTNode, packageParentNode: ASTNode) {
if (packageNode.treeNext.isWhiteSpace()) {
return
}
if (!packageNode.treeNext.isEmptyImportList()) {
packageParentNode.addChild(ASTFactory.whitespace("\n"), packageNode.treeNext)
} else {
// IMPORT_LIST without imports is after PACKAGE_NODE
// WHITE_SPACE needs to be after IMPORT_LIST only
packageParentNode.addChild(ASTFactory.whitespace("\n"), packageNode.treeNext.treeNext)
}
}

/**
* checking and fixing package directive if it does not match with the directory where the file is stored
*/
Expand Down Expand Up @@ -314,5 +327,7 @@ class PackageNaming(configRules: List<RulesConfig>) : DiktatRule(
* For kotlin multiplatform projects directories for targets from [kmmTargets] are supported.
*/
val languageDirNames = listOf("src", "java", "kotlin") + kmmTargets.flatMap { listOf("${it}Main", "${it}Test") }

private fun ASTNode.isEmptyImportList() = elementType == IMPORT_LIST && children().none()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION
import org.jetbrains.kotlin.KtNodeTypes.THIS_EXPRESSION
import org.jetbrains.kotlin.KtNodeTypes.THROW
import org.jetbrains.kotlin.KtNodeTypes.TYPE_REFERENCE
import org.jetbrains.kotlin.com.intellij.lang.ASTFactory
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl
Expand Down Expand Up @@ -232,11 +233,15 @@ class KdocMethods(configRules: List<RulesConfig>) : DiktatRule(
"${node.getIdentifierName()!!.text} (${missingParameters.joinToString()})", node.startOffset, node) {
val beforeTag = kdocTags?.find { it.knownTag == KDocKnownTag.RETURN }
?: kdocTags?.find { it.knownTag == KDocKnownTag.THROWS }
missingParameters.forEach {
missingParameters.filterNotNull().forEach { missingParameter ->
kdoc?.insertTagBefore(beforeTag?.node) {
addChild(LeafPsiElement(KDocTokens.TAG_NAME, "@param"))
addChild(PsiWhiteSpaceImpl(" "))
addChild(LeafPsiElement(KDocTokens.MARKDOWN_LINK, it))
addChild(ASTFactory.leaf(KDocTokens.TAG_NAME, "@param"))
addChild(ASTFactory.whitespace(" "))
val kdocMarkdownLink = ASTFactory.composite(KDocTokens.MARKDOWN_LINK)
.also { addChild(it) }
val kdocName = ASTFactory.composite(KDocElementTypes.KDOC_NAME)
.also { kdocMarkdownLink.addChild(it) }
kdocName.addChild(ASTFactory.leaf(KtTokens.IDENTIFIER, missingParameter))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import com.saveourtool.diktat.util.FixTestBase
import generated.WarningNames
import org.junit.jupiter.api.Tag
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir
import java.nio.file.Path

class PackagePathFixTest : FixTestBase(
"test/paragraph1/naming/package/src/main/kotlin",
Expand Down Expand Up @@ -68,4 +70,32 @@ class PackagePathFixTest : FixTestBase(
fun `fix missing package name with a proper location`() {
fixAndCompare("com/saveourtool/diktat/some/name/FixMissingExpected.kt", "com/saveourtool/diktat/some/name/FixMissingTest.kt")
}

@Test
@Tag(WarningNames.PACKAGE_NAME_MISSING)
fun `several empty lines after package`(@TempDir tempDir: Path) {
fixAndCompareContent(
expectedContent = """
package com.saveourtool.diktat
/**
* @param bar
* @return something
*/
fun foo1(bar: Bar): Baz {
// placeholder
}
""".trimIndent(),
actualContent = """
/**
* @param bar
* @return something
*/
fun foo1(bar: Bar): Baz {
// placeholder
}
""".trimIndent(),
subFolder = "src/main/kotlin/com/saveourtool/diktat",
tempDir = tempDir,
).assertSuccessful()
}
}
Loading

0 comments on commit d981125

Please sign in to comment.