Skip to content

Commit a2aed2f

Browse files
committed
Merge branch 'liufengyun-expectation-specs' into 3.1.x
2 parents 8e8f9b2 + c2d219b commit a2aed2f

File tree

12 files changed

+306
-35
lines changed

12 files changed

+306
-35
lines changed

project/GenScalaTestDotty.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,10 @@ object GenScalaTestDotty {
178178
def genTest(targetDir: File, version: String, scalaVersion: String): Seq[File] = {
179179
copyFiles("scalatest-test/src/test/scala/org/scalatest", "org/scalatest", targetDir,
180180
List(
181-
"AssertionsSpec.scala",
182-
"ShouldCompileSpec.scala",
183-
"ShouldNotCompileSpec.scala",
181+
"AssertionsSpec.scala",
182+
"ExpectationsSpec.scala",
183+
"ShouldCompileSpec.scala",
184+
"ShouldNotCompileSpec.scala",
184185
"ShouldNotTypeCheckSpec.scala"
185186
)
186187
) /*++

project/GenScalacticDotty.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,6 @@ object GenScalacticDotty {
159159
"OrSpec.scala", // Compilation error to be investigated further.
160160
"PrettifierSpec.scala", // Test failed with java.lang.IllegalAccessException
161161
"RequirementsSpec.scala", // Error during macro expansion
162-
"SnapshotsSpec.scala", // Pending macro implementation
163162
"TolerantEquivalenceSpec.scala", // Compilation error to be investigated further.
164163
"TripleEqualsSpec.for210" // Old staff, we shall delete this soon.
165164
)) ++

project/scalatest.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1209,7 +1209,7 @@ object ScalatestBuild {
12091209
Def.task {
12101210
GenScalaTestNative.genTest((sourceManaged in Test).value / "scala", version.value, scalaVersion.value)
12111211
}.taskValue
1212-
},
1212+
},
12131213
sourceGenerators in Test +=
12141214
Def.task {
12151215
GenGen.genTestForNative((sourceManaged in Test).value, version.value, scalaVersion.value)
@@ -2133,8 +2133,8 @@ object ScalatestBuild {
21332133

21342134
import dotty.tools.sbtplugin.DottyPlugin.autoImport._
21352135
// List of available night build at https://repo1.maven.org/maven2/ch/epfl/lamp/dotty-compiler_0.14/
2136-
//lazy val dottyVersion = dottyLatestNightlyBuild.get
2137-
lazy val dottyVersion = "0.14.0-bin-20190403-d00a7ba-NIGHTLY"
2136+
lazy val dottyVersion = dottyLatestNightlyBuild.get
2137+
// lazy val dottyVersion = "0.14.0-bin-20190403-d00a7ba-NIGHTLY"
21382138
lazy val dottySettings = List(
21392139
scalaVersion := dottyVersion,
21402140
libraryDependencies := libraryDependencies.value.map(_.withDottyCompat(scalaVersion.value)),

scalactic.dotty/src/main/scala/org/scalactic/BooleanMacro.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@ import scala.tasty._
2121
object BooleanMacro {
2222
def parse(condition: Expr[Boolean], prettifier: Expr[Prettifier])(implicit refl: Reflection): Expr[Bool] = {
2323
import refl._
24-
implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make(this.getClass.getClassLoader)
2524
import util._
2625

27-
def exprStr: String = condition.show
26+
// TODO: remove once `Expr[T].show` handles color correctly
27+
def (str: String) clean: String = str.replaceAll("\u001B\\[[;\\d]*m", "")
28+
29+
def exprStr: String = condition.show.clean
2830
def defaultCase = '{ Bool.simpleMacroBool($condition, ${exprStr.toExpr}, $prettifier) }
2931
def isImplicitMethodType(tp: Type): Boolean =
3032
Type.IsMethodType.unapply(tp).flatMap(tp => if tp.isImplicit then Some(true) else None).nonEmpty

scalactic.dotty/src/main/scala/org/scalactic/Requirements.scala

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ object RequirementsMacro {
233233
*/
234234
def require(condition: Expr[Boolean], prettifier: Expr[Prettifier], clue: Expr[Any])(implicit refl: Reflection): Expr[Unit] = {
235235
import refl._
236-
236+
237237
val bool = BooleanMacro.parse(condition, prettifier)
238238
'{ Requirements.requirementsHelper.macroRequire($bool, $clue) }
239239
}
@@ -247,7 +247,7 @@ object RequirementsMacro {
247247
*/
248248
def requireState(condition: Expr[Boolean], prettifier: Expr[Prettifier], clue: Expr[Any])(implicit refl: Reflection): Expr[Unit] = {
249249
import refl._
250-
250+
251251
val bool = BooleanMacro.parse(condition, prettifier)
252252
'{ Requirements.requirementsHelper.macroRequireState($bool, $clue) }
253253
}
@@ -261,7 +261,9 @@ object RequirementsMacro {
261261
*/
262262
def requireNonNull(arguments: Expr[Seq[Any]], prettifier: Expr[Prettifier], pos: Expr[source.Position])(implicit reflect: Reflection): Expr[Unit] = {
263263
import reflect._
264-
implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make(this.getClass.getClassLoader)
264+
265+
// TODO: remove once `Expr[T].show` handles color correctly
266+
def (str: String) clean: String = str.replaceAll("\u001B\\[[;\\d]*m", "")
265267

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

271273
val argStr: List[Expr[String]] = arguments.unseal.underlyingArgument match {
272274
case Typed(Repeated(args, _), _) => // only sequence literal
273-
args.map(arg => arg.seal.cast[Any].show.toExpr)
275+
args.map(arg => arg.seal.cast[Any].show.clean.toExpr)
274276
case _ =>
275277
throw QuoteError("requireNonNull can only be used with sequence literal, not `seq : _*`")
276278
}
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
/*
2+
* Copyright 2001-2014 Artima, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.scalactic
17+
18+
import scala.quoted._
19+
import scala.tasty._
20+
21+
/**
22+
* Case class that stores the name and value of a variable or expression.
23+
*
24+
* <p>
25+
* See the main documentation for trait <a href="Snapshots.html"><code>Snapshots</code></a> for more information and examples.
26+
* </p>
27+
*
28+
* @param name the name of the expression
29+
* @param value the value of the expression
30+
*/
31+
final case class Snapshot(name: String, value: Any) {
32+
33+
/**
34+
* Overriden <code>toString</code> to print in {name} = {value} format.
35+
*
36+
* @return string in {name} = {value} format
37+
*/
38+
override def toString: String = Resources.variableWasValue(name, Prettifier.default(value))
39+
}
40+
41+
/**
42+
* <p>Trait that provides a <code>snap</code> method that takes one or more arguments and results in a
43+
* <a href="SnapshotSeq.html"><code>SnapshotSeq</code></a>, whose <code>toString</code> lists the names
44+
* and values of each argument.
45+
*
46+
* <p>
47+
* The intended use case of this trait is to help you write debug and log
48+
* messages that give a "snapshot" of program state. Here's an example:
49+
* </p>
50+
*
51+
* <pre class="stREPL">
52+
* scala&gt; import Snapshots._
53+
* import Snapshots._
54+
*
55+
* scala&gt; snap(a, b, c, d, e, f)
56+
* res3: org.scalactic.SnapshotSeq = a was 1, b was 2, c was 3, d was 4, e was null, f was null
57+
* </pre>
58+
*
59+
* <p><code>SnapshotSeq</code> offers a <code>lines</code> method that places each variable name/value pair on its own line:<p>
60+
*
61+
* <pre class="stREPL">
62+
* scala&gt; snap(a, b, c, d, e, f).lines
63+
* res4: String =
64+
* a was 1
65+
* b was 2
66+
* c was 3
67+
* d was 4
68+
* e was null
69+
* f was null
70+
* </pre>
71+
*
72+
* <p>
73+
* 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:
74+
* </p>
75+
*
76+
* <pre class="stREPL">
77+
* scala&gt; snap(a, b, c, d, e, f).mkString("Wow! ", ", and ", ". That's so awesome!")
78+
* 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!
79+
* </pre>
80+
*/
81+
trait Snapshots {
82+
83+
/**
84+
* Snap the given expressions.
85+
*
86+
* @param expressions expressions to be snapped
87+
* @return an <code>IndexedSeq</code> of <code>Snapshot</code> for the given expressions.
88+
*/
89+
inline def snap(expressions: Any*): SnapshotSeq = ${ SnapshotsMacro.snap('expressions) }
90+
}
91+
92+
/**
93+
* An <code>IndexedSeq[Snapshot]</code> providing <code>toString</code> and <code>lines</code> methods that
94+
* can be useful for debug and log messages about program state.
95+
*
96+
* <p>
97+
* See the main documentation for trait <a href="Snapshots.html"><code>Snapshots</code></a> for more information and examples.
98+
* </p>
99+
*/
100+
final class SnapshotSeq(underlying: collection.immutable.IndexedSeq[Snapshot]) extends collection.immutable.IndexedSeq[Snapshot] {
101+
102+
/**
103+
* Selects an element by its index in the sequence.
104+
*
105+
* <p>
106+
* This method invokes <code>apply</code> on the underlying immutable <code>IndexedSeq[String]</code>, passing in <code>idx</code>, and returns the result.
107+
* </p>
108+
*
109+
* @param idx the index to select
110+
* @return the element of this sequence at index <code>idx</code>, where 0 indicates the first element
111+
*/
112+
def apply(idx: Int): Snapshot = underlying.apply(idx)
113+
114+
/**
115+
* The length of this sequence.
116+
*
117+
* <p>
118+
* This method invokes <code>length</code> on the underlying immutable <code>IndexedSeq[String]</code> and returns the result.
119+
* </p>
120+
*
121+
* @return the number of elements in this sequence
122+
*/
123+
def length: Int = underlying.length
124+
125+
/**
126+
* Appends a string element to this sequence, if it doesn't already exist in the sequence.
127+
*
128+
* <p>
129+
* If the string element already exists in this sequence, this method returns itself. If not,
130+
* this method returns a new <code>MultiSelOptionSeq</code> with the passed value appended to the
131+
* end of the original <code>MultiSelOptionSeq</code>.
132+
* </p>
133+
*
134+
* @param the string element to append to this sequence
135+
* @return a <code>MultiSelOptionSeq</code> that contains the passed string value
136+
*/
137+
def +(value: Snapshot): SnapshotSeq = {
138+
if (!underlying.contains(value))
139+
new SnapshotSeq(underlying :+ value)
140+
else
141+
this
142+
}
143+
144+
/**
145+
* Removes a string element to this sequence, if it already exists in the sequence.
146+
*
147+
* <p>
148+
* If the string element does not already exist in this sequence, this method returns itself. If the element
149+
* is contained in this sequence, this method returns a new <code>MultiSelOptionSeq</code> with the passed value
150+
* removed from the the original <code>MultiSelOptionSeq</code>, leaving any other elements in the same order.
151+
* </p>
152+
*
153+
* @param the string element to append to this sequence
154+
* @return a <code>MultiSelOptionSeq</code> that contains the passed string value
155+
*/
156+
def -(value: Snapshot): SnapshotSeq = {
157+
if (underlying.contains(value))
158+
new SnapshotSeq(underlying.filter(_ != value))
159+
else
160+
this
161+
}
162+
163+
/**
164+
* The default way to present the result of the <code>snap</code> method of trait </code>Snapshots</code>.
165+
*
166+
* Here's an example:
167+
*
168+
* <pre class="stREPL">
169+
* scala&gt; snap(a, b, c, d, e, f)
170+
* res3: org.scalactic.SnapshotSeq = a was 1, b was 2, c was 3, d was 4, e was null, f was null
171+
* </pre>
172+
*/
173+
override def toString: String = mkString(", ")
174+
175+
/**
176+
* An alternate way to present the result of the <code>snap</code> method of trait </code>Snapshots</code> that
177+
* puts each variable or expression on its own line.
178+
*
179+
* Here's an example:
180+
*
181+
* <pre class="stREPL">
182+
* scala&gt; snap(a, b, c, d, e, f).lines
183+
* res4: String =
184+
* a was 1
185+
* b was 2
186+
* c was 3
187+
* d was 4
188+
* e was null
189+
* f was null
190+
* </pre>
191+
*/
192+
def lines: String = mkString("\n")
193+
}
194+
195+
object SnapshotSeq {
196+
def apply(snapshots: Snapshot*): SnapshotSeq = new SnapshotSeq(Vector(snapshots: _*))
197+
}
198+
199+
/**
200+
* Companion object that facilitates the importing of <code>Snapshots</code> members as
201+
* an alternative to mixing it in. One use case is to import <code>Snapshots</code> members so you can use
202+
* them in the Scala interpreter:
203+
*
204+
* <pre class="stREPL">
205+
* $scala -classpath scalatest.jar
206+
* Welcome to Scala version 2.10.3.final (Java HotSpot(TM) Client VM, Java xxxxxx).
207+
* Type in expressions to have them evaluated.
208+
* Type :help for more information.
209+
* &nbsp;
210+
* scala&gt; import org.scalactic.Snapshots._
211+
* import org.scalatest.Snapshots._
212+
* &nbsp;
213+
* scala&gt; val a = 8
214+
* a: Int = 8
215+
*&nbsp;
216+
* scala&gt; snap(a)
217+
* res0: scala.collection.immutable.Vector[org.scalactic.Snapshot] = Vector(a = 8)
218+
* </pre>
219+
*/
220+
object Snapshots extends Snapshots
221+
222+
object SnapshotsMacro {
223+
224+
def snap(expressions: Expr[Seq[Any]])(implicit refl: Reflection): Expr[SnapshotSeq] = {
225+
import refl._
226+
// TODO: remove once `Expr[T].show` handles color correctly
227+
def (str: String) clean: String = str.replaceAll("\u001B\\[[;\\d]*m", "")
228+
229+
def liftSeq(args: Seq[Expr[Snapshot]]): Expr[Seq[Snapshot]] = args match {
230+
case x :: xs => '{ ($x) +: ${ liftSeq(xs) } }
231+
case Nil => '{ Seq(): Seq[Snapshot] }
232+
}
233+
234+
val snapshots: List[Expr[Snapshot]] = expressions.unseal.underlyingArgument match {
235+
case Typed(Repeated(args, _), _) => // only sequence literal
236+
args.map { arg =>
237+
val str = arg.seal.cast[Any].show.clean.toExpr
238+
'{ Snapshot($str, ${ arg.seal.cast[Any] }) }
239+
}
240+
case arg =>
241+
throw QuoteError("snap can only be used with sequence literal, not `seq : _*`")
242+
}
243+
244+
val argumentsS: Expr[Seq[Snapshot]] = liftSeq(snapshots)
245+
'{ SnapshotSeq($argumentsS : _*) }
246+
}
247+
}

scalactic.dotty/src/main/scala/org/scalactic/source/TypeInfoMacro.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ object TypeInfoMacro {
2929
def genTypeInfo[T](tp: Type[T])(implicit refl: Reflection): Expr[TypeInfo[T]] = {
3030
import refl._
3131

32-
val name = typeOf(tp).show.toExpr
32+
// TODO: remove once `Expr[T].show` handles color correctly
33+
def (str: String) clean: String = str.replaceAll("\u001B\\[[;\\d]*m", "")
34+
35+
val name = tp.show.clean.toExpr
3336
'{ TypeInfo[$tp]($name) }
3437
}
3538
}

0 commit comments

Comments
 (0)