Skip to content

Commit

Permalink
don't swallow a newline when replacing dependency with preceding blan…
Browse files Browse the repository at this point in the history
…k line

fixes #443
  • Loading branch information
RBusarow committed Mar 13, 2022
1 parent 0ce2e4b commit 7d9815a
Show file tree
Hide file tree
Showing 3 changed files with 314 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ fun McProject.addDependency(
val oldStatement = markerDeclaration.statementWithSurroundingText
val newStatement = newDeclaration.statementWithSurroundingText

// the `prefixIfNot("\n")` here is important.
// It needs to match what we're doing if we delete a dependency. Otherwise, we wind up adding
// or removing newlines instead of just modifying the dependencies.
// See https://github.com/RBusarow/ModuleCheck/issues/443
val combinedStatement = newStatement.plus(oldStatement.prefixIfNot("\n"))

val buildFileText = buildFile.readText()
Expand Down Expand Up @@ -86,7 +90,11 @@ fun McProject.removeDependencyWithDelete(
val text = buildFile.readText()

buildFile.writeText(
text.replaceFirst(declaration.statementWithSurroundingText + '\n', "")
// the `prefixIfNot("\n")` here is important.
// It needs to match what we're doing if we add a new dependency. Otherwise, we wind up adding
// or removing newlines instead of just modifying the dependencies.
// See https://github.com/RBusarow/ModuleCheck/issues/443
text.replaceFirst(declaration.statementWithSurroundingText.prefixIfNot("\n"), "")
)

if (configuredDependency is ConfiguredProjectDependency) {
Expand Down
264 changes: 264 additions & 0 deletions modulecheck-core/src/test/kotlin/modulecheck/core/MustBeApiTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import modulecheck.parsing.gradle.ConfigurationName
import modulecheck.parsing.gradle.SourceSetName
import modulecheck.runtime.test.ProjectFindingReport.mustBeApi
import modulecheck.runtime.test.RunnerTest
import modulecheck.testing.createSafely
import modulecheck.utils.child
import org.junit.jupiter.api.Test

class MustBeApiTest : RunnerTest() {
Expand Down Expand Up @@ -222,6 +224,268 @@ class MustBeApiTest : RunnerTest() {
)
}

// https://github.com/RBusarow/ModuleCheck/issues/443
@Test
fun `switching to api dependency after a blank line should preserve all newlines -- kotlin`() {

val lib1 = project(":lib1") {
addSource(
"com/modulecheck/lib1/Lib1Class.kt",
"""
package com.modulecheck.lib1
class Lib1Class
"""
)
}

val lib2 = project(":lib2") {

buildFile {
"""
plugins {
kotlin("jvm")
}
"""
}

addSource(
"com/modulecheck/lib2/Lib2Class.kt",
"""
package com.modulecheck.lib2
class Lib2Class
"""
)
}

val lib3 = project(":lib3") {

buildFile {
"""
plugins {
kotlin("jvm")
}
"""
}

addSource(
"com/modulecheck/lib3/Lib3Class.kt",
"""
package com.modulecheck.lib3
class Lib3Class
"""
)
}

val lib4 = project(":lib4") {
addDependency(ConfigurationName.implementation, lib1)
addDependency(ConfigurationName.implementation, lib2)
addDependency(ConfigurationName.implementation, lib3)

buildFile {
"""
plugins {
kotlin("jvm")
}
dependencies {
implementation(project(path = ":lib1"))
implementation(project(path = ":lib2"))
implementation(project(path = ":lib3"))
}
"""
}

addSource(
"com/modulecheck/lib4/Lib4Class.kt",
"""
package com.modulecheck.lib4
import com.modulecheck.lib1.Lib1Class
import com.modulecheck.lib2.Lib2Class
import com.modulecheck.lib3.Lib3Class
val lib1Class = Lib1Class()
val lib2Class = Lib2Class()
val lib3Class = Lib3Class()
"""
)
}

run().isSuccess shouldBe true

lib4.buildFile shouldHaveText """
plugins {
kotlin("jvm")
}
dependencies {
api(project(path = ":lib1"))
api(project(path = ":lib2"))
api(project(path = ":lib3"))
}
"""

logger.parsedReport() shouldBe listOf(
":lib4" to listOf(
mustBeApi(
fixed = true,
configuration = "implementation",
dependency = ":lib1",
position = "6, 3"
),
mustBeApi(
fixed = true,
configuration = "implementation",
dependency = ":lib2",
position = "8, 3"
),
mustBeApi(
fixed = true,
configuration = "implementation",
dependency = ":lib3",
position = "9, 3"
)
)
)
}

// https://github.com/RBusarow/ModuleCheck/issues/443
@Test
fun `switching to api dependency after a blank line should preserve all newlines -- groovy`() {

val lib1 = project(":lib1") {
addSource(
"com/modulecheck/lib1/Lib1Class.kt",
"""
package com.modulecheck.lib1
class Lib1Class
"""
)
}

val lib2 = project(":lib2") {

buildFile {
"""
plugins {
kotlin("jvm")
}
"""
}

addSource(
"com/modulecheck/lib2/Lib2Class.kt",
"""
package com.modulecheck.lib2
class Lib2Class
"""
)
}

val lib3 = project(":lib3") {

buildFile {
"""
plugins {
kotlin("jvm")
}
"""
}

addSource(
"com/modulecheck/lib3/Lib3Class.kt",
"""
package com.modulecheck.lib3
class Lib3Class
"""
)
}

val lib4 = project(":lib4") {
addDependency(ConfigurationName.implementation, lib1)
addDependency(ConfigurationName.implementation, lib2)
addDependency(ConfigurationName.implementation, lib3)

buildFile.delete()
buildFile = projectDir.child("build.gradle")
.createSafely(
"""
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.6.10'
}
dependencies {
implementation project(':lib1')
implementation project(':lib2')
implementation project(':lib3')
}
""".trimIndent()
)

addSource(
"com/modulecheck/lib4/Lib4Class.kt",
"""
package com.modulecheck.lib4
import com.modulecheck.lib1.Lib1Class
import com.modulecheck.lib2.Lib2Class
import com.modulecheck.lib3.Lib3Class
val lib1Class = Lib1Class()
val lib2Class = Lib2Class()
val lib3Class = Lib3Class()
"""
)
}

run().isSuccess shouldBe true

lib4.buildFile shouldHaveText """
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.6.10'
}
dependencies {
api project(':lib1')
api project(':lib2')
api project(':lib3')
}
"""

logger.parsedReport() shouldBe listOf(
":lib4" to listOf(
mustBeApi(
fixed = true,
configuration = "implementation",
dependency = ":lib1",
position = "6, 3"
),
mustBeApi(
fixed = true,
configuration = "implementation",
dependency = ":lib2",
position = "8, 3"
),
mustBeApi(
fixed = true,
configuration = "implementation",
dependency = ":lib3",
position = "9, 3"
)
)
)
}

@Test
fun `private property from implementation with auto-correct should not be changed`() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,47 @@ internal class KotlinDependencyBlockParserTest : ProjectTest() {
)
}

@Test
fun `blank line between dependencies`() {
val block = KotlinDependencyBlockParser()
.parse(
"""
dependencies {
api(testFixtures(project(":lib1")))
api(testFixtures(project(":lib2")))
implementation(testFixtures(project(":lib3")))
}
"""
).single()

block.settings shouldBe listOf(
ModuleDependencyDeclaration(
moduleRef = StringRef(":lib1"),
moduleAccess = """project(":lib1")""",
configName = ConfigurationName.api,
declarationText = """api(testFixtures(project(":lib1")))""",
statementWithSurroundingText = """ api(testFixtures(project(":lib1")))"""
),
ModuleDependencyDeclaration(
moduleRef = StringRef(":lib2"),
moduleAccess = """project(":lib2")""",
configName = ConfigurationName.api,
declarationText = """api(testFixtures(project(":lib2")))""",
statementWithSurroundingText = """|
| api(testFixtures(project(":lib2")))
""".trimMargin()
),
ModuleDependencyDeclaration(
moduleRef = StringRef(":lib3"),
moduleAccess = """project(":lib3")""",
configName = ConfigurationName.implementation,
declarationText = """implementation(testFixtures(project(":lib3")))""",
statementWithSurroundingText = """ implementation(testFixtures(project(":lib3")))"""
),
)
}

@Test
fun `string module dependency declaration with testFixtures should be parsed`() {
val block = KotlinDependencyBlockParser()
Expand Down

0 comments on commit 7d9815a

Please sign in to comment.