Skip to content

Commit

Permalink
Merge branch 'expectation-specs' of https://github.com/liufengyun/sca…
Browse files Browse the repository at this point in the history
…latest into liufengyun-expectation-specs
  • Loading branch information
bvenners committed Apr 12, 2019
2 parents 8e8f9b2 + d805f67 commit c2d219b
Show file tree
Hide file tree
Showing 12 changed files with 306 additions and 35 deletions.
7 changes: 4 additions & 3 deletions project/GenScalaTestDotty.scala
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,10 @@ object GenScalaTestDotty {
def genTest(targetDir: File, version: String, scalaVersion: String): Seq[File] = {
copyFiles("scalatest-test/src/test/scala/org/scalatest", "org/scalatest", targetDir,
List(
"AssertionsSpec.scala",
"ShouldCompileSpec.scala",
"ShouldNotCompileSpec.scala",
"AssertionsSpec.scala",
"ExpectationsSpec.scala",
"ShouldCompileSpec.scala",
"ShouldNotCompileSpec.scala",
"ShouldNotTypeCheckSpec.scala"
)
) /*++
Expand Down
1 change: 0 additions & 1 deletion project/GenScalacticDotty.scala
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,6 @@ object GenScalacticDotty {
"OrSpec.scala", // Compilation error to be investigated further.
"PrettifierSpec.scala", // Test failed with java.lang.IllegalAccessException
"RequirementsSpec.scala", // Error during macro expansion
"SnapshotsSpec.scala", // Pending macro implementation
"TolerantEquivalenceSpec.scala", // Compilation error to be investigated further.
"TripleEqualsSpec.for210" // Old staff, we shall delete this soon.
)) ++
Expand Down
6 changes: 3 additions & 3 deletions project/scalatest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1209,7 +1209,7 @@ object ScalatestBuild {
Def.task {
GenScalaTestNative.genTest((sourceManaged in Test).value / "scala", version.value, scalaVersion.value)
}.taskValue
},
},
sourceGenerators in Test +=
Def.task {
GenGen.genTestForNative((sourceManaged in Test).value, version.value, scalaVersion.value)
Expand Down Expand Up @@ -2133,8 +2133,8 @@ object ScalatestBuild {

import dotty.tools.sbtplugin.DottyPlugin.autoImport._
// List of available night build at https://repo1.maven.org/maven2/ch/epfl/lamp/dotty-compiler_0.14/
//lazy val dottyVersion = dottyLatestNightlyBuild.get
lazy val dottyVersion = "0.14.0-bin-20190403-d00a7ba-NIGHTLY"
lazy val dottyVersion = dottyLatestNightlyBuild.get
// lazy val dottyVersion = "0.14.0-bin-20190403-d00a7ba-NIGHTLY"
lazy val dottySettings = List(
scalaVersion := dottyVersion,
libraryDependencies := libraryDependencies.value.map(_.withDottyCompat(scalaVersion.value)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ import scala.tasty._
object BooleanMacro {
def parse(condition: Expr[Boolean], prettifier: Expr[Prettifier])(implicit refl: Reflection): Expr[Bool] = {
import refl._
implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make(this.getClass.getClassLoader)
import util._

def exprStr: String = condition.show
// TODO: remove once `Expr[T].show` handles color correctly
def (str: String) clean: String = str.replaceAll("\u001B\\[[;\\d]*m", "")

def exprStr: String = condition.show.clean
def defaultCase = '{ Bool.simpleMacroBool($condition, ${exprStr.toExpr}, $prettifier) }
def isImplicitMethodType(tp: Type): Boolean =
Type.IsMethodType.unapply(tp).flatMap(tp => if tp.isImplicit then Some(true) else None).nonEmpty
Expand Down
10 changes: 6 additions & 4 deletions scalactic.dotty/src/main/scala/org/scalactic/Requirements.scala
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ object RequirementsMacro {
*/
def require(condition: Expr[Boolean], prettifier: Expr[Prettifier], clue: Expr[Any])(implicit refl: Reflection): Expr[Unit] = {
import refl._

val bool = BooleanMacro.parse(condition, prettifier)
'{ Requirements.requirementsHelper.macroRequire($bool, $clue) }
}
Expand All @@ -247,7 +247,7 @@ object RequirementsMacro {
*/
def requireState(condition: Expr[Boolean], prettifier: Expr[Prettifier], clue: Expr[Any])(implicit refl: Reflection): Expr[Unit] = {
import refl._

val bool = BooleanMacro.parse(condition, prettifier)
'{ Requirements.requirementsHelper.macroRequireState($bool, $clue) }
}
Expand All @@ -261,7 +261,9 @@ object RequirementsMacro {
*/
def requireNonNull(arguments: Expr[Seq[Any]], prettifier: Expr[Prettifier], pos: Expr[source.Position])(implicit reflect: Reflection): Expr[Unit] = {
import reflect._
implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make(this.getClass.getClassLoader)

// TODO: remove once `Expr[T].show` handles color correctly
def (str: String) clean: String = str.replaceAll("\u001B\\[[;\\d]*m", "")

def liftSeq(args: Seq[Expr[String]]): Expr[Seq[String]] = args match {
case x :: xs => '{ ($x) +: ${ liftSeq(xs) } }
Expand All @@ -270,7 +272,7 @@ object RequirementsMacro {

val argStr: List[Expr[String]] = arguments.unseal.underlyingArgument match {
case Typed(Repeated(args, _), _) => // only sequence literal
args.map(arg => arg.seal.cast[Any].show.toExpr)
args.map(arg => arg.seal.cast[Any].show.clean.toExpr)
case _ =>
throw QuoteError("requireNonNull can only be used with sequence literal, not `seq : _*`")
}
Expand Down
247 changes: 247 additions & 0 deletions scalactic.dotty/src/main/scala/org/scalactic/Snapshots.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
/*
* Copyright 2001-2014 Artima, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.scalactic

import scala.quoted._
import scala.tasty._

/**
* Case class that stores the name and value of a variable or expression.
*
* <p>
* See the main documentation for trait <a href="Snapshots.html"><code>Snapshots</code></a> for more information and examples.
* </p>
*
* @param name the name of the expression
* @param value the value of the expression
*/
final case class Snapshot(name: String, value: Any) {

/**
* Overriden <code>toString</code> to print in {name} = {value} format.
*
* @return string in {name} = {value} format
*/
override def toString: String = Resources.variableWasValue(name, Prettifier.default(value))
}

/**
* <p>Trait that provides a <code>snap</code> method that takes one or more arguments and results in a
* <a href="SnapshotSeq.html"><code>SnapshotSeq</code></a>, whose <code>toString</code> lists the names
* and values of each argument.
*
* <p>
* The intended use case of this trait is to help you write debug and log
* messages that give a "snapshot" of program state. Here's an example:
* </p>
*
* <pre class="stREPL">
* scala&gt; import Snapshots._
* import Snapshots._
*
* scala&gt; snap(a, b, c, d, e, f)
* res3: org.scalactic.SnapshotSeq = a was 1, b was 2, c was 3, d was 4, e was null, f was null
* </pre>
*
* <p><code>SnapshotSeq</code> offers a <code>lines</code> method that places each variable name/value pair on its own line:<p>
*
* <pre class="stREPL">
* scala&gt; snap(a, b, c, d, e, f).lines
* res4: String =
* a was 1
* b was 2
* c was 3
* d was 4
* e was null
* f was null
* </pre>
*
* <p>
* Or, because a <code>SnapshotSeq</code> is a <code>IndexedSeq[Snapshot]</code>, you can process it just like any other <code>Seq</code>, for example:
* </p>
*
* <pre class="stREPL">
* scala&gt; snap(a, b, c, d, e, f).mkString("Wow! ", ", and ", ". That's so awesome!")
* res6: String = Wow! a was 1, and b was 2, and c was 3, and d was 4, and e was null, and f was null. That's so awesome!
* </pre>
*/
trait Snapshots {

/**
* Snap the given expressions.
*
* @param expressions expressions to be snapped
* @return an <code>IndexedSeq</code> of <code>Snapshot</code> for the given expressions.
*/
inline def snap(expressions: Any*): SnapshotSeq = ${ SnapshotsMacro.snap('expressions) }
}

/**
* An <code>IndexedSeq[Snapshot]</code> providing <code>toString</code> and <code>lines</code> methods that
* can be useful for debug and log messages about program state.
*
* <p>
* See the main documentation for trait <a href="Snapshots.html"><code>Snapshots</code></a> for more information and examples.
* </p>
*/
final class SnapshotSeq(underlying: collection.immutable.IndexedSeq[Snapshot]) extends collection.immutable.IndexedSeq[Snapshot] {

/**
* Selects an element by its index in the sequence.
*
* <p>
* This method invokes <code>apply</code> on the underlying immutable <code>IndexedSeq[String]</code>, passing in <code>idx</code>, and returns the result.
* </p>
*
* @param idx the index to select
* @return the element of this sequence at index <code>idx</code>, where 0 indicates the first element
*/
def apply(idx: Int): Snapshot = underlying.apply(idx)

/**
* The length of this sequence.
*
* <p>
* This method invokes <code>length</code> on the underlying immutable <code>IndexedSeq[String]</code> and returns the result.
* </p>
*
* @return the number of elements in this sequence
*/
def length: Int = underlying.length

/**
* Appends a string element to this sequence, if it doesn't already exist in the sequence.
*
* <p>
* If the string element already exists in this sequence, this method returns itself. If not,
* this method returns a new <code>MultiSelOptionSeq</code> with the passed value appended to the
* end of the original <code>MultiSelOptionSeq</code>.
* </p>
*
* @param the string element to append to this sequence
* @return a <code>MultiSelOptionSeq</code> that contains the passed string value
*/
def +(value: Snapshot): SnapshotSeq = {
if (!underlying.contains(value))
new SnapshotSeq(underlying :+ value)
else
this
}

/**
* Removes a string element to this sequence, if it already exists in the sequence.
*
* <p>
* If the string element does not already exist in this sequence, this method returns itself. If the element
* is contained in this sequence, this method returns a new <code>MultiSelOptionSeq</code> with the passed value
* removed from the the original <code>MultiSelOptionSeq</code>, leaving any other elements in the same order.
* </p>
*
* @param the string element to append to this sequence
* @return a <code>MultiSelOptionSeq</code> that contains the passed string value
*/
def -(value: Snapshot): SnapshotSeq = {
if (underlying.contains(value))
new SnapshotSeq(underlying.filter(_ != value))
else
this
}

/**
* The default way to present the result of the <code>snap</code> method of trait </code>Snapshots</code>.
*
* Here's an example:
*
* <pre class="stREPL">
* scala&gt; snap(a, b, c, d, e, f)
* res3: org.scalactic.SnapshotSeq = a was 1, b was 2, c was 3, d was 4, e was null, f was null
* </pre>
*/
override def toString: String = mkString(", ")

/**
* An alternate way to present the result of the <code>snap</code> method of trait </code>Snapshots</code> that
* puts each variable or expression on its own line.
*
* Here's an example:
*
* <pre class="stREPL">
* scala&gt; snap(a, b, c, d, e, f).lines
* res4: String =
* a was 1
* b was 2
* c was 3
* d was 4
* e was null
* f was null
* </pre>
*/
def lines: String = mkString("\n")
}

object SnapshotSeq {
def apply(snapshots: Snapshot*): SnapshotSeq = new SnapshotSeq(Vector(snapshots: _*))
}

/**
* Companion object that facilitates the importing of <code>Snapshots</code> members as
* an alternative to mixing it in. One use case is to import <code>Snapshots</code> members so you can use
* them in the Scala interpreter:
*
* <pre class="stREPL">
* $scala -classpath scalatest.jar
* Welcome to Scala version 2.10.3.final (Java HotSpot(TM) Client VM, Java xxxxxx).
* Type in expressions to have them evaluated.
* Type :help for more information.
* &nbsp;
* scala&gt; import org.scalactic.Snapshots._
* import org.scalatest.Snapshots._
* &nbsp;
* scala&gt; val a = 8
* a: Int = 8
*&nbsp;
* scala&gt; snap(a)
* res0: scala.collection.immutable.Vector[org.scalactic.Snapshot] = Vector(a = 8)
* </pre>
*/
object Snapshots extends Snapshots

object SnapshotsMacro {

def snap(expressions: Expr[Seq[Any]])(implicit refl: Reflection): Expr[SnapshotSeq] = {
import refl._
// TODO: remove once `Expr[T].show` handles color correctly
def (str: String) clean: String = str.replaceAll("\u001B\\[[;\\d]*m", "")

def liftSeq(args: Seq[Expr[Snapshot]]): Expr[Seq[Snapshot]] = args match {
case x :: xs => '{ ($x) +: ${ liftSeq(xs) } }
case Nil => '{ Seq(): Seq[Snapshot] }
}

val snapshots: List[Expr[Snapshot]] = expressions.unseal.underlyingArgument match {
case Typed(Repeated(args, _), _) => // only sequence literal
args.map { arg =>
val str = arg.seal.cast[Any].show.clean.toExpr
'{ Snapshot($str, ${ arg.seal.cast[Any] }) }
}
case arg =>
throw QuoteError("snap can only be used with sequence literal, not `seq : _*`")
}

val argumentsS: Expr[Seq[Snapshot]] = liftSeq(snapshots)
'{ SnapshotSeq($argumentsS : _*) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ object TypeInfoMacro {
def genTypeInfo[T](tp: Type[T])(implicit refl: Reflection): Expr[TypeInfo[T]] = {
import refl._

val name = typeOf(tp).show.toExpr
// TODO: remove once `Expr[T].show` handles color correctly
def (str: String) clean: String = str.replaceAll("\u001B\\[[;\\d]*m", "")

val name = tp.show.clean.toExpr
'{ TypeInfo[$tp]($name) }
}
}
Loading

0 comments on commit c2d219b

Please sign in to comment.