Files
2026-10-29 00:07:27 +01:00

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)
}
}