summaryrefslogtreecommitdiff
path: root/src/library/scala/testing/Show.scala
blob: 32d32d4a0cdc401db723623b9a88b536d97dae7b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package scala.testing

/** Classes inheriting trait `Show` can test their member methods using the notattion
 *  'meth(arg_1, ..., arg_n), where `meth' is the name of the method and `arg_1,...,arg_n' are
 *  the arguments. The only difference to a normal method call is the leading quote character (').
 *  A quoted method call like the one above will produces a legible diagnostic to be printed on Console.
 *  It is of the form
 *
 *    meth(arg_1, ..., arg_n)  gives  <result>
 *
 *  where <result> is the result of evaluating the call.
 */
trait Show {

  /** The result class of wrapper `symApply`.
   *  Prints out diagnostics of method applications.
   */
  class SymApply(f: Symbol) {
    def apply[A](args: A*) {
      println(test(f, args: _*))
    }
  }

  /** An implicit definition that adds an apply method to Symbol which forwards to `test`.
   */
  implicit def symApply(sym: Symbol) = new SymApply(sym)

  /** Apply method with name of given symbol `f` to given arguments and return
   *  a result diagnostics.
   */
  def test[A](f: Symbol, args: A*): String = {
    val args1 = args map (_.asInstanceOf[AnyRef])
    def testMethod(meth: java.lang.reflect.Method): String =
      f.name+"("+(args mkString ",")+")  gives  "+
      {
        try {
          meth.invoke(this, args1: _*)
        } catch {
          case ex: IllegalAccessException => ex
          case ex: IllegalArgumentException => ex
          case ex: java.lang.reflect.InvocationTargetException => ex
        }
      }
    getClass.getMethods.toList filter (_.getName == f.name) match {
      case List() =>
        f.name+" is not defined"
      case List(m) =>
        testMethod(m)
      case ms => // multiple methods, disambiguate by number of arguments
        ms filter (_.getParameterTypes.length == args.length) match {
          case List() =>
            testMethod(ms.head) // go ahead anyway, to get an exception
          case List(m) =>
            testMethod(m)
          case ms =>
            "cannot disambiguate between multiple implementations of "+f.name
        }
    }
  }
}