Declaring more specific method

What is a protected def ? I’d like to override the test method in my test case class so that it simply prints a prolog and epilog before running tests. Is protected there to keep me from doing that?

I’m creating test cases like the following.

import org.scalatest._

class MapColoringTestSuite extends FunSuite {

  import MapColoring._

  test("coloring") { ... do some testing stuff ...}
}

When I examine the code for test I find it is defined like this

trait FunSuiteLike extends TestSuite with TestRegistration with Informing with Notifying with Alerting with Documenting { thisSuite =>

   /// ... stuff deleted

   protected def test(testName: String, testTags: Tag*)(testFun: => Any /* Assertion */)(implicit pos: source.Position): Unit = { ...}

}  

How can I override test in my local class MapColoringTestSuite so that it prints something which encoded the testName string, but then passes its arguments testName and testTags on to the next most applicable test method?

In place of passing testFun, I’d like to pass something like {println(s"testing $testName") ;testFun; println(s"finished $testName")}. How to make sure that the existence of my override method does not interfere with the implicit argument in the next method?

a protected def can’t be accessed from the “outside”, where outside means a class that’s not a subclass of the defining class.

You can override it, and also call the super method, e.g.

override def test(testName: String, testTags: Tag*)(testFun: => Any /* Assertion */)(implicit pos: source.Position): Unit = {
  println("prelude")
  super.test(testName, testTags :_*)(testFun)
  println("epilog")
}

Thanks, but is the 3rd argument list correct? Is the implicit argument correct? Aren’t there potentially different implicit visible from this direclaration site than in the superclass which has already been compiled long ago? Do I need to pass (pos) as 3rd argument list?

If I omit the 3rd argument lest of test altogether, the compiler complains that

Error:(27, 16) method test overrides nothing.
Note: the super classes of class MapColoringTestSuite contain the following, non final members named test:
protected def test(testName: String,testTags: org.scalatest.Tag*)(testFun: => Any)(implicit pos: org.scalactic.source.Position): Unit
  override def test(testName: String, testTags: Tag*)(testFun: =>Any) = {

Here’s what I’m trying.


class MapColoringTestSuite extends FunSuite {
  override def test(testName: String, testTags: Tag*)(testFun: =>Any)(implicit pos: source.Position):Unit = {
    super.test(testName, testTags :_*){
      println(s"starting $testName")
      testFun
      println(s"finished $testName")
    }
  }
...
}

IntelliJ complains that source in source.Position cannot be resolved, and the compiler gives the following error

Error:(27, 85) not found: value source
  override def test(testName: String, testTags: Tag*)(testFun: =>Any)(implicit pos: source.Position):Unit = {
import org.scalactic.source
1 Like

Great this gem seems to work. Here is an example of the working code. I think it might be useful to other people as well.


class MapColoringTestSuite extends FunSuite {
  import org.scalactic.source
  override def test(testName: String, testTags: Tag*)(testFun: =>Any)(implicit pos: source.Position):Unit = {
    // (apply #'call-next-method testName testTags)
    super.test(testName, testTags :_*){
      println(s"=== starting $testName")
      testFun
      println(s"=== finished $testName")
    }
  }
  import MapColoring._

  test("coloring") {
    Bdd.withNewBddHash {
      val nodes: List[String] = List("a", "b", "c", "d")
      val uniDirectionalGraph: Map[String, Set[String]] = Map("a" -> Set(),
                                                              "b" -> Set("a"),
                                                              "c" -> Set("a"),
                                                              "d" -> Set("c", "b"))
      val biDirectionalGraph: Map[String, Set[String]] = Map("a" -> Set("b","c"),
                                                             "b" -> Set("a","d"),
                                                             "c" -> Set("a","d"),
                                                             "d" -> Set("c", "b"))

      val colors = Array("red", "green", "blue", "yellow")
      val (colorization, bdd) = graphToBdd(nodes,
                                           uniDirectionalGraph,
                                           biDirectionalGraph,
                                           4,
                                           (n,size)=>println(s"plot $n $size"),
                                           List(),
                                           1)
      bdd.visitSatisfyingAssignments { (assignTrue,assignFalse) =>
        val colorMapping: Map[String, String] = assignColors(colorization, assignTrue,assignFalse, colors)
        colors.foreach { color =>
          val sameColorStates = colorMapping.filterKeys { state => colorMapping(state) == color }.keys
          for {state1 <- sameColorStates
               state2 <- sameColorStates
               if state1 != state2
               } locally {
            // assert that if two states on the map are colored the same, then they don't connect
            //   i.e., they don't share a border as per uniDirectionalGraph
            assert(!uniDirectionalGraph(state1).contains(state2))
            assert(!uniDirectionalGraph(state2).contains(state1))
          }
        }
      }
    }
    println("finished test coloring")
  }

  test("europe"){
    println("starting test europe")
    europeMapColoringTest(30)
    println("finished test europe")
  }
}

Now when I run the tests (interactively I see output like the following.

=== starting coloring
4 (4) states: List(a, b, c, d)
plot 1.0 1.0
plot 2.0 19.0
plot 3.0 19.0
plot 4.0 57.0
finished test coloring
=== finished coloring
1 Like

BTW martin, I don’t understand the testTags :_* syntax. Is that just something to memorise, or does it have a meaning I can understand? the : does not seem like a type declaration which is its usual purpose.

The idea is that it is like a type hint: if you declare it def foo(numbers: Int*), and you call it with a list, you also use the * to show it should be used as Int*, but since it already are Int's, you can use _ for Int, so instead of foo(List(1, 2, 3): Int*) you use foo(List(1, 2, 3): _*)

Or at least, that’s how I always interpreted it.

It would make sense to me if you could also call it with Int* instead of _*, but you can’t. I don’t know why that is.

1 Like

Is there somewhere a definitive list of all the different meanings of _ ?

Not that I know of. There is a bunch here: https://stackoverflow.com/questions/8000903/what-are-all-the-uses-of-an-underscore-in-scala

The intuition is “whatever”. In practice, that intuition often works out. Unless it doesn’t.

I’d say it doesn’t mean “whatever” in the testTags :_* example. It rather means something very special casey.

I believe it aims for _* is to be read as to interpret your Seq as repeated (*) whatever’s in there (_)

It’s a bit of a stretch and I don’t think it quite accomplishes what it aims for.

This is IMO one of those “where it doesn’t”, along with higher kinded types and seq extractors (case Seq(xs @ _*)

1 Like

Underscore means “unnamed”.

Unnamed doesn’t work well for HKTs IMO.

Example?

You’ve already gotten the answers to that, I see, but context is helpful: that parameter is more or less magically synthesized by Scalactic (which underlies ScalaTest), to pass the calling source position around. Basically, it is how ScalaTest reports which line the error came from.

This can be hugely useful when you have your own utility methods wrapping assert – if you add that implicit pos: Position as a parameter list on your method, ScalaTest will report the caller when there is an assertion failure, instead of the literal assert() call in your utility method. The result is often much more useful error messages.

class Foo[F[_]]