From fc73203d0b0823038403975b7d3334665afa8350 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Mon, 19 Feb 2018 18:42:24 +0000 Subject: [PATCH] Fix validID & expand tests Make sure that we generate valid ID (according to matches(ID, s)) so that we properly test the new validID implementation. And that's what led to the bug fix. :) --- .../sbt/internal/util/complete/Parsers.scala | 2 +- .../src/test/scala/DefaultParsersSpec.scala | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/internal/util-complete/src/main/scala/sbt/internal/util/complete/Parsers.scala b/internal/util-complete/src/main/scala/sbt/internal/util/complete/Parsers.scala index c148095ec..1120ed173 100644 --- a/internal/util-complete/src/main/scala/sbt/internal/util/complete/Parsers.scala +++ b/internal/util-complete/src/main/scala/sbt/internal/util/complete/Parsers.scala @@ -317,7 +317,7 @@ object DefaultParsers extends Parsers with ParserMain { /** Returns `true` if `s` parses successfully according to [[ID]].*/ def validID(s: String): Boolean = { // Handwritten version of `matches(ID, s)` because validID turned up in profiling. - def isIdChar(c: Char): Boolean = Character.isLetterOrDigit(c) || (c == '_') + def isIdChar(c: Char): Boolean = Character.isLetterOrDigit(c) || (c == '-') || (c == '_') @tailrec def isRestIdChar(cur: Int, s: String, length: Int): Boolean = if (cur < length) isIdChar(s.charAt(cur)) && isRestIdChar(cur + 1, s, length) diff --git a/internal/util-complete/src/test/scala/DefaultParsersSpec.scala b/internal/util-complete/src/test/scala/DefaultParsersSpec.scala index ce3a6b2e9..253a4216b 100644 --- a/internal/util-complete/src/test/scala/DefaultParsersSpec.scala +++ b/internal/util-complete/src/test/scala/DefaultParsersSpec.scala @@ -8,10 +8,21 @@ package sbt.internal.util package complete -import org.scalacheck._, Prop._ +import org.scalacheck._, Gen._, Prop._ object DefaultParsersSpec extends Properties("DefaultParsers") { - import DefaultParsers._ + import DefaultParsers.{ ID, isIDChar, matches, validID } - property("validID == matches(ID, s)") = forAll((s: String) => validID(s) == matches(ID, s)) + property("∀ s ∈ String: validID(s) == matches(ID, s)") = forAll( + (s: String) => validID(s) == matches(ID, s)) + + property("∀ s ∈ genID: matches(ID, s)") = forAll(genID)(s => matches(ID, s)) + property("∀ s ∈ genID: validID(s)") = forAll(genID)(s => validID(s)) + + private val chars: Seq[Char] = Char.MinValue to Char.MaxValue + private val genID: Gen[String] = + for { + c <- oneOf(chars filter (_.isLetter)) + cs <- listOf(oneOf(chars filter isIDChar)) + } yield (c :: cs).mkString }