52 lines
2.1 KiB
Scala
52 lines
2.1 KiB
Scala
package snake
|
|
|
|
import java.nio.file.{Files, Path, Paths}
|
|
import scala.jdk.CollectionConverters.*
|
|
|
|
class PuritySuite extends munit.FunSuite:
|
|
private val srcDir = Paths.get(sys.props.getOrElse("user.dir", ".")).resolve("src")
|
|
|
|
// Files that are allowed to touch the outside world (a future web/ directory lives outside src/).
|
|
private def excluded(file: Path): Boolean = file.getFileName.toString == "Runtime.scala"
|
|
|
|
private val banned: List[(String, scala.util.matching.Regex, String)] = List(
|
|
("var", """\bvar\b""".r, "var n = 0"),
|
|
("mutable", """\bmutable\b""".r, "val b = scala.collection.mutable.ListBuffer[Int]()"),
|
|
("while", """\bwhile\b""".r, "while n < 3 do n += 1"),
|
|
("scala.util.Random", """\bscala\.util\.Random\b""".r, "val r = scala.util.Random.nextInt()"),
|
|
("System.", """\bSystem\.""".r, "val t = System.currentTimeMillis()"),
|
|
("println", """\bprintln\b""".r, "println(\"hi\")")
|
|
)
|
|
|
|
private def stripComments(code: String): String =
|
|
code.replaceAll("""(?s)/\*.*?\*/""", "").replaceAll("""(?m)//.*$""", "")
|
|
|
|
private def violations(code: String): List[String] =
|
|
val clean = stripComments(code)
|
|
banned.collect { case (name, re, _) if re.findFirstIn(clean).isDefined => name }
|
|
|
|
private def scalaFiles(dir: Path): List[Path] =
|
|
if !Files.exists(dir) then Nil
|
|
else Files.walk(dir).iterator.asScala.filter(f => f.toString.endsWith(".scala")).toList.sorted
|
|
|
|
banned.foreach { (name, _, sample) =>
|
|
test(s"purity scanner flags a known-bad sample using $name") {
|
|
assert(violations(sample).contains(name))
|
|
}
|
|
}
|
|
|
|
test("purity scanner ignores banned words inside comments") {
|
|
val code = "// var mutable println\n/* while (x) System.exit(1) */\nval a = 1 // scala.util.Random\n"
|
|
assertEquals(violations(code), Nil)
|
|
}
|
|
|
|
test("purity scanner accepts ordinary pure code") {
|
|
assertEquals(violations("def f(xs: List[Int]): List[Int] = xs.map(_ + 1)"), Nil)
|
|
}
|
|
|
|
scalaFiles(srcDir).filterNot(excluded).foreach { f =>
|
|
test(s"purity: ${srcDir.relativize(f)} has no banned constructs") {
|
|
assertEquals(violations(Files.readString(f)), Nil)
|
|
}
|
|
}
|