import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe.definitions._
import scala.reflect.runtime.{currentMirror => cm}
import scala.reflect.ClassTag
object Test extends App {
def key(sym: Symbol) = {
sym match {
// initialize parameter symbols
case meth: MethodSymbol => meth.params.flatten.map(_.typeSignature)
}
sym + ": " + sym.typeSignature
}
def convert(value: Any, tpe: Type) = {
import scala.runtime.BoxesRunTime._
if (tpe =:= typeOf[Byte]) toByte(value)
else if (tpe =:= typeOf[Short]) toShort(value)
else if (tpe =:= typeOf[Char]) toCharacter(value)
else if (tpe =:= typeOf[Int]) toInteger(value)
else if (tpe =:= typeOf[Long]) toLong(value)
else if (tpe =:= typeOf[Float]) toFloat(value)
else if (tpe =:= typeOf[Double]) toDouble(value)
else if (tpe =:= typeOf[String]) value.toString
else if (tpe =:= typeOf[Boolean]) value.asInstanceOf[Boolean]
else throw new Exception(s"not supported: value = $value, tpe = $tpe")
}
def test[T: ClassTag](tpe: Type, receiver: T, method: String, args: Any*) {
def wrap[T](op: => T) =
try {
var result = op.asInstanceOf[AnyRef]
if (scala.runtime.ScalaRunTime.isArray(result))
result = scala.runtime.ScalaRunTime.toObjectArray(result).toList
println(s"[${result.getClass}] =======> $result")
} catch {
case ex: Throwable =>
val realex = scala.reflect.runtime.ReflectionUtils.unwrapThrowable(ex)
println(realex.getClass + ": " + realex.getMessage)
}
val meth = tpe.declaration(newTermName(method).encodedName.toTermName)
val testees = if (meth.isMethod) List(meth.asMethod) else meth.asTerm.alternatives.map(_.asMethod)
testees foreach (testee => {
val convertedArgs = args.zipWithIndex.map { case (arg, i) => convert(arg, testee.params.flatten.apply(i).typeSignature) }
print(s"testing ${tpe.typeSymbol.name}.$method(${testee.params.flatten.map(_.typeSignature).mkString(','.toString)}) with receiver = $receiver and args = ${convertedArgs.map(arg => arg + ' '.toString + arg.getClass).toList}: ")
wrap(cm.reflect(receiver).reflectMethod(testee)(convertedArgs: _*))
})
}
def header(tpe: Type) {
println(s"============\n$tpe")
println("it's important to print the list of Byte's members")
println("if some of them change (possibly, adding and/or removing magic symbols), we must update this test")
tpe.members.toList.sortBy(key).foreach(sym => println(key(sym)))
}
def testNumeric[T: ClassTag](tpe: Type, value: T) {
header(tpe)
List("toByte", "toShort", "toChar", "toInt", "toLong", "toFloat", "toDouble") foreach (meth => test(tpe, value, meth))
test(tpe, value, "==", 2)
test(tpe, value, "!=", 2)
test(tpe, value, "<", 2)
test(tpe, value, "<=", 2)
test(tpe, value, ">", 2)
test(tpe, value, ">=", 2)
test(tpe, value, "+", 2)
test(tpe, value, "-", 2)
test(tpe, value, "*", 2)
test(tpe, value, "/", 2)
test(tpe, value, "%", 2)
}
def testIntegral[T: ClassTag](tpe: Type, value: T) {
testNumeric(tpe, value)
test(tpe, value, "unary_~")
test(tpe, value, "unary_+")
test(tpe, value, "unary_-")
test(tpe, value, "<<", 2)
test(tpe, value, ">>", 2)
test(tpe, value, ">>>", 2)
test(tpe, value, "|", 2)
test(tpe, value, "&", 2)
test(tpe, value, "^", 2)
}
def testBoolean() {
header(typeOf[Boolean])
test(typeOf[Boolean], true, "unary_!")
test(typeOf[Boolean], true, "==", true)
test(typeOf[Boolean], true, "!=", true)
test(typeOf[Boolean], true, "||", true)
test(typeOf[Boolean], true, "&&", true)
test(typeOf[Boolean], true, "|", true)
test(typeOf[Boolean], true, "&", true)
test(typeOf[Boolean], true, "^", true)
}
def testUnit() {
header(typeOf[Unit])
}
testNumeric(typeOf[Byte], 2.toByte)
testNumeric(typeOf[Short], 2.toShort)
testNumeric(typeOf[Char], 2.toChar)
testNumeric(typeOf[Int], 2.toInt)
testNumeric(typeOf[Long], 2.toLong)
testNumeric(typeOf[Float], 2.toFloat)
testNumeric(typeOf[Double], 2.toDouble)
testBoolean()
testUnit()
}