How to use fixture-context objects with async specs in ScalaTest? - scala

I'm trying to use fixture-context objects with async testing in ScalaTest.
The naive approach of simply combining the two doesn't compile. For example:
import org.scalatest.AsyncWordSpec
import scala.collection.GenTraversableOnce
import scala.concurrent.{ExecutionContext, Future}
import scala.math.Numeric.IntIsIntegral
trait Adder[T] {
implicit def num: Numeric[T]
def add(number: T): Unit
def result: Future[T]
}
object Foo {
def doubleSum[T](adder: Adder[T], numbers: GenTraversableOnce[T])(implicit ec: ExecutionContext): Future[T] = {
numbers.foreach(adder.add)
val num = adder.num
import num._
adder.result.map(result => result + result)
}
}
class FooSpec extends AsyncWordSpec {
trait IntAdder {
val adder = new Adder[Int] {
override implicit val num = IntIsIntegral
private var sum = Future.successful(num.zero)
override def add(number: Int): Unit = sum = sum.map(_ + number)
override def result: Future[Int] = sum
}
}
"Testing" should {
"be productive" in new IntAdder {
Foo.doubleSum(adder, Seq(1, 2, 3)).map(sum => assert(sum == 12))
}
}
}
This fails to compile with:
Error:(37, 11) type mismatch;
found : FooSpec.this.IntAdder
required: scala.concurrent.Future[org.scalatest.compatible.Assertion]
new IntAdder {
This is a legitimate error but I'm wondering what ways there are of solving this in a ScalaTest style.
I want to keep the fixture-context object since that allows me to use the stackable trait pattern.

What about:
import org.scalatest.compatible.Assertion
class FooSpec extends AsyncWordSpec {
def withIntAdder(test: Adder[Int] => Future[Assertion]): Future[Assertion] = {
val adder = new Adder[Int] { ... }
test(adder)
}
"Testing" should {
"be productive" in withIntAdder { adder =>
Foo.doubleSum(adder, Seq(1, 2, 3)).map(sum => assert(sum == 12))
}
}
}
Or
class FooSpec extends AsyncWordSpec {
trait IntAdder {
val adder = new Adder[Int] {
override implicit val num = IntIsIntegral
private var sum = Future.successful(num.zero)
override def add(number: Int): Unit = sum = sum.map(_ + number)
override def result: Future[Int] = sum
}
}
trait SomeMoreFixture {
}
"Testing" should {
"be productive" in {
val fixture = new IntAdder with SomeMoreFixture
import fixture._
Foo.doubleSum(adder, Seq(1, 2, 3)).map(sum => assert(sum == 12))
}
}
}

The best solution I have come up with so far is to do something like:
class FooSpec extends AsyncWordSpec {
trait IntAdder {
... // Same as in the question
val assertion: Future[compatible.Assertion]
}
"Testing" should {
"be productive" in new IntAdder {
val assertion = Foo.doubleSum(adder, Seq(1, 2, 3)).map(sum => assert(sum == 12))
}.assertion
}
}
I was hoping to reduce it down slightly more into:
class FooSpec extends AsyncWordSpec {
trait IntAdder extends (() => Future[compatible.Assertion]) {
... // Same as in the question
val assertion: Future[compatible.Assertion]
override def apply(): Future[Assertion] = assertion
}
"Testing" should {
"be productive" in new IntAdder {
val assertion = Foo.doubleSum(adder, Seq(1, 2, 3)).map(sum => assert(sum == 12))
}()
}
}
However this also doesn't compile due to:
Error:(42, 10) ';' expected but '(' found.
}()

You could have a mix of the fixture-context objects and the loan-fixtures methods patterns.
Something like this:
class FooSpec extends AsyncWordSpec {
// Fixture-context object
trait IntAdder {
val adder = new Adder[Int] {
override implicit val num = IntIsIntegral
private var sum = Future.successful(num.zero)
override def add(number: Int): Unit = sum = sum.map(_ + number)
override def result: Future[Int] = sum
}
}
// Loan-fixture method
def withContext(testCode: IntAdder => Future[compatible.Assertion]): Future[compatible.Assertion] = {
val context = new IntAdder {}
testCode(context)
}
"Testing" should {
"be productive" in withContext { context =>
import context._
Foo.doubleSum(adder, Seq(1, 2, 3)).map(sum => assert(sum == 12))
}
}
}

Related

In Scala, how to deal with heterogeneous list of the same parameterized type

I have an array of Any (in real life, it's a Spark Row, but it's sufficient to isolate the problem)
object Row {
val buffer : Array[Any] = Array(42, 21, true)
}
And I want to apply some operations on its elements.
So, I've defined a simple ADT to define a compute operation on a type A
trait Op[A] {
def cast(a: Any) : A = a.asInstanceOf[A]
def compute(a: A) : A
}
case object Count extends Op[Int] {
override def compute(a: Int): Int = a + 1
}
case object Exist extends Op[Boolean] {
override def compute(a: Boolean): Boolean = a
}
Given that I have a list of all operations and I know which operation is to apply to each element, let's use these operations.
object GenericsOp {
import Row._
val ops = Seq(Count, Exist)
def compute() = {
buffer(0) = ops(0).compute(ops(0).cast(buffer(0)))
buffer(1) = ops(0).compute(ops(0).cast(buffer(1)))
buffer(2) = ops(1).compute(ops(1).cast(buffer(2)))
}
}
By design, for a given op, types are aligned between cast and combine. But unfortunately the following code does not compile. The error is
Type mismatch, expected: _$1, actual: AnyVal
Is there a way to make it work ?
I've found a workaround by using abstract type member instead of type parameter.
object AbstractOp extends App {
import Row._
trait Op {
type A
def compute(a: A) : A
}
case object Count extends Op {
type A = Int
override def compute(a: Int): Int = a + 1
}
case object Exist extends Op {
type A = Boolean
override def compute(a: Boolean): Boolean = a
}
val ops = Seq(Count, Exist)
def compute() = {
val op0 = ops(0)
val op1 = ops(1)
buffer(0) = ops(0).compute(buffer(0).asInstanceOf[op0.A])
buffer(1) = ops(0).compute(buffer(1).asInstanceOf[op0.A])
buffer(2) = ops(1).compute(buffer(2).asInstanceOf[op1.A])
}
}
Is there a better way ?
It seems that your code can be simplified by making Op[A] extend Any => A:
trait Op[A] extends (Any => A) {
def cast(a: Any) : A = a.asInstanceOf[A]
def compute(a: A) : A
def apply(a: Any): A = compute(cast(a))
}
case object Count extends Op[Int] {
override def compute(a: Int): Int = a + 1
}
case object Exist extends Op[Boolean] {
override def compute(a: Boolean): Boolean = a
}
object AbstractOp {
val buffer: Array[Any] = Array(42, 21, true)
val ops: Array[Op[_]] = Array(Count, Count, Exist)
def main(args: Array[String]): Unit = {
for (i <- 0 until buffer.size) {
buffer(i) = ops(i)(buffer(i))
}
println(buffer.mkString("[", ",", "]"))
}
}
Since it's asInstanceOf everywhere anyway, it does not make the code any less safe than what you had previously.
Update
If you cannot change the Op interface, then invoking cast and compute is a bit more cumbersome, but still possible:
trait Op[A] {
def cast(a: Any) : A = a.asInstanceOf[A]
def compute(a: A) : A
}
case object Count extends Op[Int] {
override def compute(a: Int): Int = a + 1
}
case object Exist extends Op[Boolean] {
override def compute(a: Boolean): Boolean = a
}
object AbstractOp {
val buffer: Array[Any] = Array(42, 21, true)
val ops: Array[Op[_]] = Array(Count, Count, Exist)
def main(args: Array[String]): Unit = {
for (i <- 0 until buffer.size) {
buffer(i) = ops(i) match {
case op: Op[t] => op.compute(op.cast(buffer(i)))
}
}
println(buffer.mkString("[", ",", "]"))
}
}
Note the ops(i) match { case op: Opt[t] => ... } part with a type-parameter in the pattern: this allows us to make sure that cast returns a t that is accepted by compute.
As a more general solution than Andrey Tyukin's, you can define the method outside Op, so it works even if Op can't be modified:
def apply[A](op: Op[A], x: Any) = op.compute(op.cast(x))
buffer(0) = apply(ops(0), buffer(0))

Apply a function to an object with generic type in Scala

I have this code
import scala.reflect.ClassTag
case class Data[T: ClassTag](list: List[T]) {
}
trait Transformation {
type T
type U
def transform(data: Data[T]) : Data[U]
}
class FromInt2String extends Transformation {
override type T = Int
override type U = String
override def transform(data: Data[T]) = new Data(List("1", "2", "3"))
}
class FromString2Int extends Transformation {
override type T = String
override type U = Int
override def transform(data: Data[T]) = new Data(List(1, 2, 3))
}
object Test extends App {
override def main(args: Array[String]) {
val data = new Data(List(1, 2, 3))
val int2String = new FromInt2String()
val data2 = int2String.transform(data)
val string2Int = new FromString2Int()
val data3 = string2Int.transform(data2)
val transformations = List(int2String, string2Int)
val data4 = transformations.foldLeft(data)((data, transformation) => {
transformation.transform(data)
})
}
}
The problem is in the foldLeft method. I can't do it because the type isn't compatible but I need to apply all the transforms in my initial object data
Any ideas how to do it?
Thanks
I've solved it using shapeless and this post
import scala.reflect.ClassTag
import shapeless._
object andThen extends Poly2 {
implicit def functions[A, B, C] = at[A => B, B => C](_ andThen _)
}
case class Data[T: ClassTag](list: List[T]) {
}
trait Transformation {
type T
type U
def transform(data: Data[T]) : Data[U]
}
class FromInt2String extends Transformation {
override type T = Int
override type U = String
override def transform(data: Data[T]) = new Data(List("1s", "2s", "3s"))
}
class FromString2Int extends Transformation {
override type T = String
override type U = Int
override def transform(data: Data[T]) = new Data(List(4, 5, 6))
}
object Test extends App {
override def main(args: Array[String]) {
val data = new Data(List(1, 2, 3))
println(data)
val int2String = new FromInt2String()
val data2 = int2String.transform(data)
println(data2)
val string2Int = new FromString2Int()
val data3 = string2Int.transform(data2)
println(data3)
val transformations = int2String.transform _ :: string2Int.transform _ :: HNil
val functions = transformations.reduceLeft(andThen)
val data4 = functions(data)
println(data4)
}
}
Thanks to all of you that help me

How to invokePrivate on a function with implicit parameters

How do I invoke XYZ.doSomething method for these classes:
XYZ.scala
object XYZ {
private def doSomething(i : Int)(implicit s: String): String {
s + i.toString
}
}
XYZTest.scala
class XYZTest extends FunSpec with PrivateMethodTester {
describe("SomeTest") {
it("Can't find a private method named: doSomething :( ") {
implicit lazy val someStr: String = "sahil"
val doSomething = PrivateMethod[String]('doSomething)
val myStr = XYZ invokePrivate doSomething(1)
assert(myStr == "sahil1")
}
}
describe("SomeTest") {
it("This doesn't even compile :( ") {
val doSomething = PrivateMethod[String]('doSomething)
val myStr = XYZ invokePrivate doSomething(1)("sahil")
assert(myStr == "sahil1")
}
}
}
Correct answer is:
object XYZ {
private def doSomething(i : Int)(implicit s: String): String = {
s + i.toString
}
}
class XYZTest extends FunSpec with PrivateMethodTester {
describe("SomeTest") {
it("Can't find a private method named: doSomething :( ") {
implicit lazy val someStr: String = "sahil"
val doSomething = PrivateMethod[String]('doSomething)
val myStr = XYZ invokePrivate doSomething(1, someStr)
assert(myStr == "sahil1")
}
}
}
Brief view on invokePrivate method shows that it does not support implicits, but looks like it treats currying argument list as general sequence of arguments
def invokePrivate[T](invocation : PrivateMethodTester.this.Invocation[T])
where args is the sequence:
final class Invocation[T](val methodName : scala.Symbol, val args : scala.Any*)

scala trait members and derivated variables

Hi am trying to write a simple hill climbing algorithm in scala .
I have State and HillClimbing that are traits.
I define them as concrete classes when I apply them to the Graph problem.
In GraphHillClimbing I receive two errors. This is because I use GraphState instead of State (observe that GraphState is also a State).
How can I solve this?
trait State {
val loc = 0
def neighbours: List[State]
def get_loc():Int = return loc
}
class GraphState(loc:Int, g: Map[Int, List[Int]]) extends State {
def neighbours():List[GraphState] =
{
def neighboursAcc(l:List[Int], acc:List[GraphState], g:Map[Int, List[Int]]):List[GraphState] =
{
if(l.isEmpty) acc
else {
val new_neig = new GraphState(l.head, g)
neighboursAcc(l.tail, List(new_neig) ++ acc, g)
}
}
neighboursAcc(g(loc), List(), g)
}
}
trait HillClimbing {
val max_iteration = 4
val start:State
def cost(state:State):Double
private def argmin(costs:List[Double]):Int = {
val best = costs.min
costs.indexOf(best)
}
private def next_best(states:List[State]):State = {
val costs = states map(x => cost(x))
val pos = argmin(costs)
states(pos)
}
def minimize():State = {
def minimizeAcc(iteration:Int, state:State):State =
{
if(iteration > max_iteration) state
else {
val neigs = state.neighbours
val next_state = next_best(neigs)
minimizeAcc(iteration+1, next_state)
}
}
minimizeAcc(0, start)
}
}
class GraphHillClimbing(start:GraphState, goal:GraphState) extends HillClimbing {
// ERROR 1 = start was State and now it is GraphState
// ERROR 2 = cost should take a State
def cost(current_state:GraphState):Double = {
val distance = goal.get_loc() - current_state.get_loc()
if(distance > 0 ) distance
else -distance
}
}
object RunHillClimbing {
def main(args: Array[String]) {
val G = Map[Int, List[Int]](1->List(2, 4, 5), 2->List(1, 3, 4), 3->List(2, 6), 4->List(1, 2, 5), 5->List(1, 4), 6->List(3))
val start = new GraphState(1, G)
val goal = new GraphState(6, G)
val hc = new GraphHillClimbing(start, goal)
print(hc.minimize())
}
}
I think this can be solved using some type parameters with type bounds.
Also in your constructor for GraphHillClimbing you should use val to indicate that the parameter start is the concrete implementation of the abstract start.
trait State[+Self] {
Self =>
def loc:Int
def neighbours: List[Self]
def get_loc():Int = return loc
}
class GraphState(val loc:Int, g: Map[Int, List[Int]]) extends State[GraphState] {
def neighbours():List[GraphState] =
{
def neighboursAcc(l:List[Int], acc:List[GraphState], g:Map[Int, List[Int]]):List[GraphState] =
{
if(l.isEmpty) acc
else {
val new_neig = new GraphState(l.head, g)
neighboursAcc(l.tail, List(new_neig) ++ acc, g)
}
}
neighboursAcc(g(loc), List(), g)
}
}
trait HillClimbing[T<:State[T]] {
val max_iteration = 4
val start:T
def cost(state:T):Double
private def argmin(costs:List[Double]):Int = {
val best = costs.min
costs.indexOf(best)
}
private def next_best(states:List[T]):T = {
val costs = states map(x => cost(x))
val pos = argmin(costs)
states(pos)
}
def minimize():T = {
def minimizeAcc(iteration:Int, state:T):T =
{
if(iteration > max_iteration) state
else {
val neigs = state.neighbours
val next_state = next_best(neigs)
minimizeAcc(iteration+1, next_state)
}
}
minimizeAcc(0, start)
}
}
class GraphHillClimbing(val start:GraphState, goal:GraphState) extends HillClimbing[GraphState] {
def cost(current_state:GraphState):Double = {
val distance = goal.get_loc() - current_state.get_loc()
if(distance > 0 ) distance
else -distance
}
}
object RunHillClimbing {
def main(args: Array[String]) {
val G = Map[Int, List[Int]](1->List(2, 4, 5), 2->List(1, 3, 4), 3->List(2, 6), 4->List(1, 2, 5), 5->List(1, 4), 6->List(3))
val start = new GraphState(1, G)
val goal = new GraphState(6, G)
val hc = new GraphHillClimbing(start, goal)
print(hc.minimize())
}
}
What I get:
error: class GraphHillClimbing needs to be abstract, since:
it has 2 unimplemented members.
/** As seen from class GraphHillClimbing, the missing signatures are as follows.
* For convenience, these are usable as stub implementations.
*/
def cost(state: this.State): Double = ???
val start: this.State = ???
class GraphHillClimbing(start:GraphState, goal:GraphState) extends HillClimbing {
^
Replace GraphState in the class with State, because inheritance
demands you'll have to handle State not GraphState.
Then replace
val loc = 0
with
def loc = 0
So you can overwrite it in GraphState.

type parameter mismatch with WeakTypeTag reflection + quasiquoting (I think!)

Inspired by travisbrown, I'm trying to use a macro to create some "smart constructors".
Given
package mypkg
sealed trait Hello[A]
case class Ohayo[A,B](a: (A,B)) extends Hello[A]
and
val smartConstructors = FreeMacros.liftConstructors[Hello]
The macro should find all the subclasses of Hello, look at their constructors, and extract a few elements to populate this tree for the "smart constructor":
q"""
def $methodName[..$typeParams](...$paramLists): $baseType =
$companionSymbol[..$typeArgs](...$argLists)
"""
I hoped to get:
val smartConstructors = new {
def ohayo[A, B](a: (A, B)): Hello[A] = Ohayo[A, B](a)
}
but instead get:
error: type mismatch;
found : (A(in class Ohayo), B(in class Ohayo))
required: ((some other)A(in class Ohayo), (some other)B(in class Ohayo))
val liftedConstructors = FreeMacros.liftConstructors[Hello]
At a glance, the tree looks ok to me:
scala> q" new { ..$wellTyped }"
res1: u.Tree =
{
final class $anon extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
def ohayo[A, B](a: (A, B)): net.arya.constructors.Hello[A] = Ohayo[A, B](a)
};
new $anon()
}
but I guess it invisibly isn't. If I naively try to freshen up the typeParams with info.typeParams.map(p => TypeName(p.name.toString)), I get "can't splice A as type parameter" when I do the quasiquoting.
Where am I going wrong? Thanks for taking a look.
-Arya
import scala.language.experimental.macros
import scala.reflect.api.Universe
import scala.reflect.macros.whitebox
class FreeMacros(val c: whitebox.Context) {
import c.universe._
import FreeMacros._
def liftedImpl[F[_]](implicit t: c.WeakTypeTag[F[_]]): Tree = {
val atc = t.tpe
val childSymbols: Set[ClassSymbol] = subCaseClassSymbols(c.universe)(atc.typeSymbol.asClass)
val wellTyped = childSymbols.map(ctorsForSymbol(c.universe)(atc)).unzip
q"new { ..${wellTyped} }"
}
}
object FreeMacros {
def liftConstructors[F[_]]: Any = macro FreeMacros.liftedImpl[F]
def smartName(name: String): String = (
name.toList match {
case h :: t => h.toLower :: t
case Nil => Nil
}
).mkString
def subCaseClassSymbols(u: Universe)(root: u.ClassSymbol): Set[u.ClassSymbol] = {
val subclasses = root.knownDirectSubclasses
val cast = subclasses.map(_.asInstanceOf[u.ClassSymbol])
val partitioned = mapped.partition(_.isCaseClass)
partitioned match {
case (caseClasses, regularClasses) => caseClasses ++ regularClasses.flatMap(r => subCaseClassSymbols(u)(r))
}
}
def ctorsForSymbol(u: Universe)(atc: u.Type)(caseClass: u.ClassSymbol): (u.DefDef, u.DefDef) = {
import u._
import internal._
// these didn't help
// def clearTypeSymbol(s: Symbol): TypeSymbol = internal.newTypeSymbol(NoSymbol, s.name.toTypeName, s.pos, if(s.isImplicit)Flag.IMPLICIT else NoFlags)
// def clearTypeSymbol2(s: Symbol): TypeSymbol = internal.newTypeSymbol(NoSymbol, s.name.toTypeName, NoPosition, if(s.isImplicit)Flag.IMPLICIT else NoFlags)
// def clearTypeDef(d: TypeDef): TypeDef = internal.typeDef(clearTypeSymbol(d.symbol))
val companionSymbol: Symbol = caseClass.companion
val info: Type = caseClass.info
val primaryCtor: Symbol = caseClass.primaryConstructor
val method = primaryCtor.asMethod
val typeParams = info.typeParams.map(internal.typeDef(_))
// val typeParams = info.typeParams.map(s => typeDef(newTypeSymbol(NoSymbol, s.name.toTypeName, NoPosition, NoFlags)))
// val typeParams = info.typeParams.map(s => internal.typeDef(clearTypeSymbol2(s)))
val typeArgs = info.typeParams.map(_.name)
val paramLists = method.paramLists.map(_.map(internal.valDef(_)))
val argLists = method.paramLists.map(_.map(_.asTerm.name))
val baseType = info.baseType(atc.typeSymbol)
val List(returnType) = baseType.typeArgs
val methodName = TermName(smartName(caseClass.name.toString))
val wellTyped =
q"""
def $methodName[..$typeParams](...$paramLists): $baseType =
$companionSymbol[..$typeArgs](...$argLists)
"""
wellTyped
}
}
P.S. I have been experimenting with toolbox.untypecheck / typecheck per this article but haven't found a working combination.
you need using
clas.typeArgs.map(_.toString).map(name => {
TypeDef(Modifiers(Flag.PARAM),TypeName(name), List(),TypeBoundsTree(EmptyTree, EmptyTree))
}
replace
info.typeParams.map(p => TypeName(p.name.toString))
it si my code
object GetSealedSubClass {
def ol3[T]: Any = macro GetSealedSubClassImpl.ol3[T]
}
class GetSealedSubClassImpl(val c: Context) {
import c.universe._
def showInfo(s: String) =
c.info(c.enclosingPosition, s.split("\n").mkString("\n |---macro info---\n |", "\n |", ""), true)
def ol3[T: c.WeakTypeTag]: c.universe.Tree = {
//get all sub class
val subClass = c.weakTypeOf[T]
.typeSymbol.asClass.knownDirectSubclasses
.map(e => e.asClass.toType)
//check type params must ia s sealed class
if (subClass.size < 1)
c.abort(c.enclosingPosition, s"${c.weakTypeOf[T]} is not a sealed class")
// get sub class constructor params
val subConstructorParams = subClass.map { e =>
//get constructor
e.members.filter(_.isConstructor)
//if the class has many Constructor then you need filter the main Constructor
.head.map(s => s.asMethod)
//get function param list
}.map(_.asMethod.paramLists.head)
.map(_.map(e => q"""${e.name.toTermName}:${e.info} """))
val outfunc = subClass zip subConstructorParams map {
case (clas, parm) =>
q"def smartConstructors[..${
clas.typeArgs.map(_.toString).map(name => {
TypeDef(Modifiers(Flag.PARAM), TypeName(name), List(), TypeBoundsTree(EmptyTree, EmptyTree))
})
}](..${parm})=${clas.typeSymbol.name.toTermName} (..${parm})"
}
val outClass =
q"""
object Term{
..${outfunc}
}
"""
showInfo(show(outClass))
q"""{
$outClass
Term
}
"""
}
}
using like this
sealed trait Hello[A]
case class Ohayo[A, B](a: (A, B)) extends Hello[A]
object GetSealed extends App {
val a = GetSealedSubClass.ol3[Hello[_]]
val b=a.asInstanceOf[ {def smartConstructors[A, B](a: (A, B)): Ohayo[A, B]}].smartConstructors(1, 2).a
println(b)
}