diff --git a/scalafix/build.sbt b/scalafix/build.sbt new file mode 100644 index 00000000..a8a23263 --- /dev/null +++ b/scalafix/build.sbt @@ -0,0 +1,96 @@ +lazy val V = _root_.scalafix.sbt.BuildInfo + +lazy val rulesCrossVersions = Seq(V.scala213, V.scala212) +lazy val scala3Version = "3.5.0" + +inThisBuild( + List( + organization := "typelevel", + homepage := Some(url("https://github.com/typelevel/weaver-test")), + licenses := List( + "Apache-2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0") + ), + semanticdbEnabled := true, + semanticdbVersion := scalafixSemanticdb.revision + ) +) + +lazy val `weaver-test` = (project in file(".")) + .aggregate( + rules.projectRefs ++ + input.projectRefs ++ + output.projectRefs ++ + tests.projectRefs: _* + ) + .settings( + publish / skip := true + ) + +lazy val rules = projectMatrix + .settings( + moduleName := "scalafix", + libraryDependencies += "ch.epfl.scala" %% "scalafix-core" % V.scalafixVersion + ) + .defaultAxes(VirtualAxis.jvm) + .jvmPlatform(rulesCrossVersions) + +lazy val input = projectMatrix + .settings( + publish / skip := true, + libraryDependencies += "com.disneystreaming" %% "weaver-cats" % "0.8.3" + ) + .defaultAxes(VirtualAxis.jvm) + .jvmPlatform(scalaVersions = rulesCrossVersions :+ scala3Version) + +lazy val output = projectMatrix + .settings( + publish / skip := true, + libraryDependencies += "com.disneystreaming" %% "weaver-cats" % "0.8.3" + ) + .defaultAxes(VirtualAxis.jvm) + .jvmPlatform(scalaVersions = rulesCrossVersions :+ scala3Version) + +lazy val testsAggregate = Project("tests", file("target/testsAggregate")) + .aggregate(tests.projectRefs: _*) + .settings( + publish / skip := true + ) + +lazy val tests = projectMatrix + .settings( + publish / skip := true, + scalafixTestkitOutputSourceDirectories := + TargetAxis + .resolve(output, Compile / unmanagedSourceDirectories) + .value, + scalafixTestkitInputSourceDirectories := + TargetAxis + .resolve(input, Compile / unmanagedSourceDirectories) + .value, + scalafixTestkitInputClasspath := + TargetAxis.resolve(input, Compile / fullClasspath).value, + scalafixTestkitInputScalacOptions := + TargetAxis.resolve(input, Compile / scalacOptions).value, + scalafixTestkitInputScalaVersion := + TargetAxis.resolve(input, Compile / scalaVersion).value + ) + .defaultAxes( + rulesCrossVersions.map(VirtualAxis.scalaABIVersion) :+ VirtualAxis.jvm: _* + ) + .jvmPlatform( + scalaVersions = Seq(V.scala212), + axisValues = Seq(TargetAxis(scala3Version)), + settings = Seq() + ) + .jvmPlatform( + scalaVersions = Seq(V.scala213), + axisValues = Seq(TargetAxis(V.scala213)), + settings = Seq() + ) + .jvmPlatform( + scalaVersions = Seq(V.scala212), + axisValues = Seq(TargetAxis(V.scala212)), + settings = Seq() + ) + .dependsOn(rules) + .enablePlugins(ScalafixTestkitPlugin) diff --git a/scalafix/input/src/main/scala/fix/RenameAssertToExpectTest.scala b/scalafix/input/src/main/scala/fix/RenameAssertToExpectTest.scala new file mode 100644 index 00000000..63785deb --- /dev/null +++ b/scalafix/input/src/main/scala/fix/RenameAssertToExpectTest.scala @@ -0,0 +1,25 @@ +/* +rule = RenameAssertToExpect +*/ +package fix +import weaver._ + +object RenameAssertToExpectTest extends SimpleIOSuite { + + pureTest("and") { + assert(1 == 1) and assert(2 == 2) && not(assert(1 == 2)) + } + + pureTest("or") { + (assert(1 == 1) or assert(2 == 1)) && + (assert(2 == 1) or assert(1 == 1)) && + not(assert(2 == 1) || assert(1 == 2)) + } + + pureTest("xor") { + (assert(1 == 1) xor assert(2 == 1)) && + (assert(2 == 1) xor assert(1 == 1)) && + not(assert(1 == 1) xor assert(2 == 2)) && + not(assert(2 == 1) xor assert(1 == 2)) + } +} diff --git a/scalafix/output/src/main/scala/fix/RenameAssertToExpectTest.scala b/scalafix/output/src/main/scala/fix/RenameAssertToExpectTest.scala new file mode 100644 index 00000000..4064e216 --- /dev/null +++ b/scalafix/output/src/main/scala/fix/RenameAssertToExpectTest.scala @@ -0,0 +1,23 @@ +package fix +import weaver._ + +object RenameAssertToExpectTest extends SimpleIOSuite { + + pureTest("and") { + expect(1 == 1) and expect(2 == 2) && not(expect(1 == 2)) + } + + pureTest("or") { + (expect(1 == 1) or expect(2 == 1)) && + (expect(2 == 1) or expect(1 == 1)) && + not(expect(2 == 1) || expect(1 == 2)) + } + + pureTest("xor") { + (expect(1 == 1) xor expect(2 == 1)) && + (expect(2 == 1) xor expect(1 == 1)) && + not(expect(1 == 1) xor expect(2 == 2)) && + not(expect(2 == 1) xor expect(1 == 2)) + } +} + diff --git a/scalafix/project/TargetAxis.scala b/scalafix/project/TargetAxis.scala new file mode 100644 index 00000000..ee368362 --- /dev/null +++ b/scalafix/project/TargetAxis.scala @@ -0,0 +1,47 @@ +import sbt._ +import sbt.internal.ProjectMatrix +import sbtprojectmatrix.ProjectMatrixPlugin.autoImport._ + +/** Use on ProjectMatrix rows to tag an affinity to a custom scalaVersion */ +case class TargetAxis(scalaVersion: String) extends VirtualAxis.WeakAxis { + + private val scalaBinaryVersion = CrossVersion.binaryScalaVersion(scalaVersion) + + override val idSuffix = s"Target${scalaBinaryVersion.replace('.', '_')}" + override val directorySuffix = s"target$scalaBinaryVersion" +} + +object TargetAxis { + + private def targetScalaVersion(virtualAxes: Seq[VirtualAxis]): String = + virtualAxes.collectFirst { case a: TargetAxis => a.scalaVersion }.get + + /** When invoked on a ProjectMatrix with a TargetAxis, lookup the project + * generated by `matrix` with a scalaVersion matching the one declared in + * that TargetAxis, and resolve `key`. + */ + def resolve[T]( + matrix: ProjectMatrix, + key: TaskKey[T] + ): Def.Initialize[Task[T]] = + Def.taskDyn { + val sv = targetScalaVersion(virtualAxes.value) + val project = matrix.finder().apply(sv) + Def.task((project / key).value) + } + + /** When invoked on a ProjectMatrix with a TargetAxis, lookup the project + * generated by `matrix` with a scalaVersion matching the one declared in + * that TargetAxis, and resolve `key`. + */ + def resolve[T]( + matrix: ProjectMatrix, + key: SettingKey[T] + ): Def.Initialize[T] = + Def.settingDyn { + val sv = targetScalaVersion(virtualAxes.value) + val project = matrix.finder().apply(sv) + Def.setting((project / key).value) + } + +} diff --git a/scalafix/project/build.properties b/scalafix/project/build.properties new file mode 100644 index 00000000..0b699c30 --- /dev/null +++ b/scalafix/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.10.2 diff --git a/scalafix/project/plugins.sbt b/scalafix/project/plugins.sbt new file mode 100644 index 00000000..2b13486e --- /dev/null +++ b/scalafix/project/plugins.sbt @@ -0,0 +1,3 @@ +resolvers += Resolver.sonatypeRepo("releases") +addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.11.1") +addSbtPlugin("com.eed3si9n" % "sbt-projectmatrix" % "0.9.2") diff --git a/scalafix/readme.md b/scalafix/readme.md new file mode 100644 index 00000000..d3418d57 --- /dev/null +++ b/scalafix/readme.md @@ -0,0 +1,7 @@ +# Scalafix rules for weaver-test + +To develop rule: +``` +sbt ~tests/test +# edit rules/src/main/scala/fix/RenameAssertToExpect.scala +``` diff --git a/scalafix/rules/src/main/resources/META-INF/services/scalafix.v1.Rule b/scalafix/rules/src/main/resources/META-INF/services/scalafix.v1.Rule new file mode 100644 index 00000000..f690e7ca --- /dev/null +++ b/scalafix/rules/src/main/resources/META-INF/services/scalafix.v1.Rule @@ -0,0 +1 @@ +fix.RenameAssertToExpect diff --git a/scalafix/rules/src/main/scala/fix/RenameAssertToExpect.scala b/scalafix/rules/src/main/scala/fix/RenameAssertToExpect.scala new file mode 100644 index 00000000..eded2ee9 --- /dev/null +++ b/scalafix/rules/src/main/scala/fix/RenameAssertToExpect.scala @@ -0,0 +1,14 @@ +package fix + +import scalafix.v1._ + +class RenameAssertToExpect extends SemanticRule("RenameAssertToExpect") { + + override def fix(implicit doc: SemanticDocument): Patch = { + val assertMethod = SymbolMatcher.normalized("weaver/Expectations.Helpers#assert.") + doc.tree.collect { + case assertMethod(tree) => Patch.renameSymbol(tree.symbol, "expect") + }.asPatch + } + +} diff --git a/scalafix/tests/src/test/scala/fix/RuleSuite.scala b/scalafix/tests/src/test/scala/fix/RuleSuite.scala new file mode 100644 index 00000000..ab80d006 --- /dev/null +++ b/scalafix/tests/src/test/scala/fix/RuleSuite.scala @@ -0,0 +1,8 @@ +package fix + +import scalafix.testkit._ +import org.scalatest.funsuite.AnyFunSuiteLike + +class RuleSuite extends AbstractSemanticRuleSuite with AnyFunSuiteLike { + runAllTests() +}