diff --git a/README.md b/README.md index e85bbc2..853921e 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ a simple of textual replacement macro language. ## Latest nontrivial changes + * Updated tests to Scala 2.12.2 + * Branching macros (choose which replacement based on a flag). See section "Altering collections in a way that causes many tests to fail". @@ -21,9 +23,11 @@ See section "Altering collections in a way that causes many tests to fail". Clone the repository and run ```bash -sbt -mem 6144 "tests/runMain tests.generated.collection.Test_All" +sbt -J-XX:MaxMetaspaceSize=1G -J-Xmx6G "tests/runMain tests.generated.collection.Test_All" ``` +(with older sbt: use `-mem 6144` in place of `-J-Xmx6G`). + If all goes well, the build process will do some compilation and code generation in project `laws`, then more compilation in project `init`, followed by more code generation and a test coverage report looking something like this: @@ -60,7 +64,7 @@ Congratuations! Your collections were quasi-comprehensively tested. If you prefer to separate the compilation and test-running phases, just run ```bash -sbt -mem 4096 tests/compile +sbt -J-Xmx4G tests/compile ``` first. This will compile the `laws` and `init` projects as necessary, and call diff --git a/build.sbt b/build.sbt index 232c4ee..e6cb9f6 100644 --- a/build.sbt +++ b/build.sbt @@ -1,5 +1,5 @@ name := "collections-laws" -version := "0.3.1" +version := "0.3.2" -scalaVersion in ThisBuild := "2.11.6" +scalaVersion in ThisBuild := "2.12.2" diff --git a/laws/src/main/resources/replacements.tests b/laws/src/main/resources/replacements.tests index a0fb5e1..bb3320e 100644 --- a/laws/src/main/resources/replacements.tests +++ b/laws/src/main/resources/replacements.tests @@ -720,7 +720,7 @@ junitFileHeader --> $LINE(import org.junit.runner.RunWith) --> $LINE(import org.junit.Test) objectHeader --> $LINE(type Q = (Long,String)) --> $LINE(val allLetters = (32 to 126).map(_.toChar).mkString) - --> $LINE(implicit val qNumeric = new Numeric[Q]{ def compare(x: Q, y: Q) = (x._1 compare y._1) match { case 0 => x._2 compare y._2; case z => z }; def fromInt(i: Int) = i match { case 0 => 0L->""; case 1 => 1L->allLetters; case _ => i.toLong -> i.toString }; def minus(x: Q, y: Q) = (x._1 - y._1) -> (x._2.reverse diff y._2.reverse).reverse; def negate(x: Q) = (-x._1) -> x._2.reverse; def plus(x: Q, y: Q) = (x._1 + y._1) -> (x._2.toSet|y._2.toSet).toList.sorted.mkString; def times(x: Q, y: Q) = (x._1*y._1) -> (x._2.toSet&y._2.toSet).toList.sorted.mkString; def toDouble(x: Q) = x._1.toDouble; def toFloat(x: Q) = x._1.toFloat; def toInt(x: Q) = x._1.toInt; def toLong(x: Q) = x._1 }) + --> $LINE(implicit val qNumeric = new Numeric[Q]{ def compare(x: Q, y: Q) = (x._1 compare y._1) match { case 0 => x._2 compare y._2; case z => z }; def fromInt(i: Int) = i match { case 0 => 0L->""; case 1 => 1L->allLetters; case _ => i.toLong -> i.toString }; def minus(x: Q, y: Q) = (x._1 - y._1) -> (x._2.reverse diff y._2.reverse).reverse; def negate(x: Q) = (-x._1) -> x._2.reverse; def plus(x: Q, y: Q) = (x._1 + y._1) -> (x._2.toSet|y._2.toSet).toList.sorted.mkString; def times(x: Q, y: Q) = (x._1*y._1) -> (x._2.toSet&y._2.toSet).toList.sorted.mkString; def toDouble(x: Q) = x._1.toDouble; def toFloat(x: Q) = x._1.toFloat; def toInt(x: Q) = x._1.toInt; def toLong(x: Q) = x._1; def parseString(str: String) = None }) --> $LINE(implicit class LsOps(ls: Q) { def <(lz: Q) = qNumeric.compare(ls, lz) < 0; def >(lz: Q) = qNumeric.compare(ls, lz) > 0; def +(lz: Q) = qNumeric.plus(ls, lz); def *(lz: Q) = qNumeric.times(ls, lz); def min(lz: Q) = if (qNumeric.compare(ls, lz) < 0) ls else lz; def max(lz: Q) = if (qNumeric.compare(ls, lz) < 0) lz else ls }) @@ -871,7 +871,7 @@ junitFileHeader --> $LINE(import org.junit.runner.RunWith) --> $LINE(import org.junit.Test) objectHeader --> $LINE(type Q = (String,Long)) --> $LINE(val allLetters = (32 to 126).map(_.toChar).mkString) - --> $LINE(implicit val qNumeric = new Numeric[Q]{ def compare(x: Q, y: Q) = (x._1 compare y._1) match { case 0 => x._2 compare y._2; case z => z }; def fromInt(i: Int) = i match { case 0 => ""->0L; case 1 => allLetters->1L; case _ => i.toString -> i.toLong }; def minus(x: Q, y: Q) = (x._1.reverse diff y._1.reverse).reverse -> (x._2 - y._2); def negate(x: Q) = x._1.reverse -> (-x._2); def plus(x: Q, y: Q) = (x._1.toSet|y._1.toSet).toList.sorted.mkString -> (x._2 + y._2); def times(x: Q, y: Q) = (x._1.toSet&y._1.toSet).toList.sorted.mkString -> (x._2*y._2); def toDouble(x: Q) = x._2.toDouble; def toFloat(x: Q) = x._2.toFloat; def toInt(x: Q) = x._2.toInt; def toLong(x: Q) = x._2 }) + --> $LINE(implicit val qNumeric = new Numeric[Q]{ def compare(x: Q, y: Q) = (x._1 compare y._1) match { case 0 => x._2 compare y._2; case z => z }; def fromInt(i: Int) = i match { case 0 => ""->0L; case 1 => allLetters->1L; case _ => i.toString -> i.toLong }; def minus(x: Q, y: Q) = (x._1.reverse diff y._1.reverse).reverse -> (x._2 - y._2); def negate(x: Q) = x._1.reverse -> (-x._2); def plus(x: Q, y: Q) = (x._1.toSet|y._1.toSet).toList.sorted.mkString -> (x._2 + y._2); def times(x: Q, y: Q) = (x._1.toSet&y._1.toSet).toList.sorted.mkString -> (x._2*y._2); def toDouble(x: Q) = x._2.toDouble; def toFloat(x: Q) = x._2.toFloat; def toInt(x: Q) = x._2.toInt; def toLong(x: Q) = x._2; def parseString(str: String) = None }) --> $LINE(implicit class LsOps(ls: Q) { def <(lz: Q) = qNumeric.compare(ls, lz) < 0; def >(lz: Q) = qNumeric.compare(ls, lz) > 0; def +(lz: Q) = qNumeric.plus(ls, lz); def *(lz: Q) = qNumeric.times(ls, lz); def min(lz: Q) = if (qNumeric.compare(ls, lz) < 0) ls else lz; def max(lz: Q) = if (qNumeric.compare(ls, lz) < 0) lz else ls }) diff --git a/laws/src/main/resources/single-line.tests b/laws/src/main/resources/single-line.tests index 36fc6ca..6aa053a 100644 --- a/laws/src/main/resources/single-line.tests +++ b/laws/src/main/resources/single-line.tests @@ -82,7 +82,7 @@ x.`toTraversable` theSameAs x !RANGE !SORTED !ARRAY !USESARRAY !N ... { val xx = x.`genericBuilder`[@A]; sameType(x, xx.result) } // Combine the following two lines into one when set issues are fixed !RANGE !SORTED !ARRAY !USESARRAY !VIEW !S ... type ROOT[TARG] = @ROOTS[TARG]; val y: Any = x; y match { case r: ROOT[_] => val xx = r.asInstanceOf[ROOT[@A]].map(identity); classOf[@CC] isAssignableFrom xx.getClass; case _ => true } -!RANGE !SORTED !ARRAY !USESARRAY !VIEW S !M FIXED8434 ... type ROOT[TARG] = @ROOTS[TARG]; val y: Any = x; y match { case r: ROOT[_] => val xx = r.asInstanceOf[ROOT[@A]].map(identity); classOf[@CC] isAssignableFrom xx.getClass; case _ => true } +!RANGE !SORTED !ARRAY !USESARRAY !VIEW S !M ... type ROOT[TARG] = @ROOTS[TARG]; val y: Any = x; y match { case r: ROOT[_] => val xx = r.asInstanceOf[ROOT[@A]].map(identity); classOf[@CC] isAssignableFrom xx.getClass; case _ => true } !RANGE !SORTED !ARRAY !VIEW M FIXED8434 ... type ROOT[TARG1,TARG2] = @ROOTMAPS[TARG1,TARG2]; val y: Any = x; y match { case m: ROOT[_, _] => val xx = m.asInstanceOf[ROOT[@K, @V]].map(identity); classOf[@CC] isAssignableFrom xx.getClass; case _ => true } // Methods that apply to most collections types @@ -232,7 +232,7 @@ sameType(x, x.`reverse`) y ... x.`endsWith`(y) == (x.`drop`(math.max(0, x.`size`-y.size)) theSameAs y) g ... x.`groupBy`(g).keySet theSameAs x.map(g).toSet g ... x.`groupBy`(g).toMap.forall{ case (k,vs) => x.filter(xi => g(xi)==k) theSameAs vs } -!ARRAY !M ... !x.`nonEmpty` || (x match { case _: scala.collection.Seq[_] => Seq(x.`head`) theSameAs x.`take`(1); case _ => true }) +!ARRAY !M ... !x.`nonEmpty` || (if (classOf[scala.collection.Seq[_]] isAssignableFrom x.getClass) Seq(x.`head`) theSameAs x.`take`(1) else true) ARRAY ... !x.`nonEmpty` || (Seq(x.`head`) theSameAs x.`take`(1)) x.`headOption` == tryO{ x.`head` } n a !ITERATOR ... n < 0 || { val k = x.`drop`(n).`takeWhile`(_ != a); x.`indexOf`(a,n) match { case -1 => k.`size` == (0 max x.size-n); case kk => n+k.size == kk && x.`drop`(kk).`head` == a } } diff --git a/project/build.properties b/project/build.properties new file mode 100644 index 0000000..133a8f1 --- /dev/null +++ b/project/build.properties @@ -0,0 +1 @@ +sbt.version=0.13.17