Skip to content

Commit

Permalink
Use correct start indices in ModulePositionScanner (#3207)
Browse files Browse the repository at this point in the history
* Test the root cause of #3206

* Reproduce #3206 as rewrite test

* Use correct start indices in ModulePositionScanner

`ModulePositionScanner` currently reports wrong substring positions if
an an artifactId is a proper substring of a groupId. With this change,
regex capturing groups are used to get the correct start indices of
substring positions of `ModulePositions`.

* Reformat test
  • Loading branch information
fthomas authored Nov 13, 2023
1 parent 7f380e0 commit 6ab25ce
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,49 +36,49 @@ object ModulePositionScanner {
fileData: FileData
): Iterator[ModulePosition] =
sbtModuleIdRegex(dependency).findAllIn(fileData.content).matchData.map { m =>
val groupId = Substring.Position.fromMatch(fileData.path, m, dependency.groupId.value)
val artifactId = Substring.Position.fromMatch(fileData.path, m, dependency.artifactId.name)
val version = Substring.Position.fromMatch(fileData.path, m, m.group(1))
val groupId = Substring.Position(fileData.path, m.start(1), dependency.groupId.value)
val artifactId = Substring.Position(fileData.path, m.start(2), dependency.artifactId.name)
val version = Substring.Position(fileData.path, m.start(3), m.group(3))
ModulePosition(groupId, artifactId, version)
}

private def sbtModuleIdRegex(dependency: Dependency): Regex = {
val g = Regex.quote(dependency.groupId.value)
val a = Regex.quote(dependency.artifactId.name)
raw""""$g"\s*%+\s*"$a"\s*%+\s*(.*)""".r
raw""""($g)"\s*%+\s*"($a)"\s*%+\s*(.*)""".r
}

private def findMillDependency(
dependency: Dependency,
fileData: FileData
): Iterator[ModulePosition] =
millDependencyRegex(dependency).findAllIn(fileData.content).matchData.map { m =>
val groupId = Substring.Position.fromMatch(fileData.path, m, dependency.groupId.value)
val artifactId = Substring.Position.fromMatch(fileData.path, m, dependency.artifactId.name)
val version = Substring.Position.fromMatch(fileData.path, m, m.group(1))
val groupId = Substring.Position(fileData.path, m.start(1), dependency.groupId.value)
val artifactId = Substring.Position(fileData.path, m.start(2), dependency.artifactId.name)
val version = Substring.Position(fileData.path, m.start(3), m.group(3))
ModulePosition(groupId, artifactId, version)
}

private def millDependencyRegex(dependency: Dependency): Regex = {
val g = Regex.quote(dependency.groupId.value)
val a = Regex.quote(dependency.artifactId.name)
raw"""["`]$g:+$a:+(.*)["`;]""".r
raw"""["`]($g):+($a):+(.*)["`;]""".r
}

private def findMavenDependency(
dependency: Dependency,
fileData: FileData
): Iterator[ModulePosition] =
mavenDependencyRegex(dependency).findAllIn(fileData.content).matchData.map { m =>
val groupId = Substring.Position.fromMatch(fileData.path, m, dependency.groupId.value)
val artifactId = Substring.Position.fromMatch(fileData.path, m, dependency.artifactId.name)
val version = Substring.Position.fromMatch(fileData.path, m, m.group(2))
val groupId = Substring.Position(fileData.path, m.start(1), dependency.groupId.value)
val artifactId = Substring.Position(fileData.path, m.start(2), dependency.artifactId.name)
val version = Substring.Position(fileData.path, m.start(4), m.group(4))
ModulePosition(groupId, artifactId, version)
}

private def mavenDependencyRegex(dependency: Dependency): Regex = {
val g = Regex.quote(dependency.groupId.value)
val a = Regex.quote(dependency.artifactId.name)
raw"""<groupId>$g</groupId>\s*<artifactId>$a(|_[^<]+)</artifactId>\s*<version>(.*)</version>""".r
raw"""<groupId>($g)</groupId>\s*<artifactId>($a)(|_[^<]+)</artifactId>\s*<version>(.*)</version>""".r
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -890,58 +890,63 @@ class RewriteTest extends FunSuite {
runApplyUpdate(update, original, expected)
}

test("issue-2877: sbt using same version in a val and a literal using a Seq addition") {
// https://github.com/scala-steward-org/scala-steward/issues/2877
test("sbt using same version in a val and a literal using a Seq addition") {
val update = ("org.scalatest".g % Nel.of(
"scalatest".a,
"scalactic".a
) % "3.2.13" %> "3.2.14").group
val original = Map(
"build.sbt" ->
"""
|val ScalaTestVersion = "3.2.13"
"""val ScalaTestVersion = "3.2.13"
|libraryDependencies ++= Seq(
| "org.scalatest" %% "scalatest" % ScalaTestVersion,
| "org.scalatest" %% "scalactic" % "3.2.13"
|)
|""".stripMargin
|)""".stripMargin
)
val expected = Map(
"build.sbt" ->
"""
|val ScalaTestVersion = "3.2.14"
"""val ScalaTestVersion = "3.2.14"
|libraryDependencies ++= Seq(
| "org.scalatest" %% "scalatest" % ScalaTestVersion,
| "org.scalatest" %% "scalactic" % "3.2.14"
|)
|""".stripMargin
|)""".stripMargin
)
runApplyUpdate(update, original, expected)
}

test("issue-2877: sbt using same version in a val and a literal using individual additions") {
// https://github.com/scala-steward-org/scala-steward/issues/2877
test("sbt using same version in a val and a literal using individual additions") {
val update = ("org.scalatest".g % Nel.of(
"scalatest".a,
"scalactic".a
) % "3.2.13" %> "3.2.14").group
val original = Map(
"build.sbt" ->
"""
|val ScalaTestVersion = "3.2.13"
"""val ScalaTestVersion = "3.2.13"
|libraryDependencies += "org.scalatest" %% "scalatest" % ScalaTestVersion
|libraryDependencies += "org.scalatest" %% "scalactic" % "3.2.13"
|""".stripMargin
)
val expected = Map(
"build.sbt" ->
"""
|val ScalaTestVersion = "3.2.14"
"""val ScalaTestVersion = "3.2.14"
|libraryDependencies += "org.scalatest" %% "scalatest" % ScalaTestVersion
|libraryDependencies += "org.scalatest" %% "scalactic" % "3.2.14"
|""".stripMargin
)
runApplyUpdate(update, original, expected)
}

// https://github.com/scala-steward-org/scala-steward/issues/3206
test("sbt module where the artifactId is also part of the groupId") {
val update = ("com.typesafe.play".g % "play".a % "2.9.0" %> "3.0.0").single
.copy(newerGroupId = Some("org.playframework".g), newerArtifactId = Some("play"))
val original = Map("build.sbt" -> """ "com.typesafe.play" %% "play" % "2.9.0" """)
val expected = Map("build.sbt" -> """ "org.playframework" %% "play" % "3.0.0" """)
runApplyUpdate(update, original, expected)
}

private def runApplyUpdate(
update: Update.Single,
files: Map[String, String],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,18 @@ class ModulePositionScannerTest extends FunSuite {
)
assertEquals(obtained, expected)
}

test("sbt module where the artifactId is also part of the groupId") {
val d = "com.typesafe.play".g % "play".a % "2.9.0"
val fd = FileData("build.sbt", s""""com.typesafe.play" %% "play" % "2.9.0"""")
val obtained = ModulePositionScanner.findPositions(d, fd)
val expected = List(
ModulePosition(
Substring.Position(fd.path, 1, d.groupId.value),
Substring.Position(fd.path, 24, d.artifactId.name),
Substring.Position(fd.path, 32, s"\"${d.version}\"")
)
)
assertEquals(obtained, expected)
}
}

0 comments on commit 6ab25ce

Please sign in to comment.