aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2013-02-25 14:55:23 -0600
committerJesse Luehrs <doy@tozt.net>2013-02-25 14:55:23 -0600
commitf4506b747bcc0fee03ccc6aa2abda02d3c6ff3ee (patch)
tree1275f54cd1368b0e8aa0b7e4f20094f6ef0667cb
parentcd84a98f8e61e87dda5bf2e7fd35a2a3d409d31c (diff)
downloadscala-test-more-f4506b747bcc0fee03ccc6aa2abda02d3c6ff3ee.tar.gz
scala-test-more-f4506b747bcc0fee03ccc6aa2abda02d3c6ff3ee.zip
make the test method hiding stuff a bit less fragile. hopefully.
-rw-r--r--src/main/scala/org/perl8/test/TestMore.scala59
-rw-r--r--src/test/scala/org/perl8/test/ExtensionTest.scala12
2 files changed, 40 insertions, 31 deletions
diff --git a/src/main/scala/org/perl8/test/TestMore.scala b/src/main/scala/org/perl8/test/TestMore.scala
index 7d5ab7b..8f60cf3 100644
--- a/src/main/scala/org/perl8/test/TestMore.scala
+++ b/src/main/scala/org/perl8/test/TestMore.scala
@@ -9,7 +9,6 @@ class TestMore (plan: Option[Plan] = None) extends Test with DelayedInit {
this(Some(plan))
def delayedInit (body: => Unit) {
- level = 0
todo = NoMessage
builder = new TestBuilder(plan, "", NoMessage)
testBody = () => body
@@ -123,17 +122,38 @@ class TestMore (plan: Option[Plan] = None) extends Test with DelayedInit {
ok(success, name)
}
+ protected def ignoreFrame (frame: StackTraceElement): Boolean = {
+ val className = frame.getClassName
+ val methodName = frame.getMethodName
+
+ // ignore everything in this class, except the hideTestMethod call which we
+ // use as a stack trace marker
+ (className == "org.perl8.test.TestMore" &&
+ methodName != "hideTestMethod") ||
+ // when you call a method in a class when the method is defined in a
+ // trait, it calls a stub which calls the real definition in the trait.
+ // the trait is represented under the hood as a class with the same name
+ // as the trait, except with $class appended. this is a gross reliance on
+ // implementation details that could change at any moment, but i don't
+ // really see any better options.
+ """\$class$""".r.findFirstIn(className).nonEmpty
+ }
+
private def failed (desc: Message) {
- val stack = Thread.currentThread.getStackTrace.drop(1)
- def findIdx (level: Int, start: Int): Int = {
- val idx = stack.indexWhere({ frame =>
- frame.getFileName != "TestMore.scala"
- }, start)
+ val stack = Thread.currentThread.getStackTrace.drop(1).filter { frame =>
+ !ignoreFrame(frame)
+ }
+ val idx = stack.lastIndexWhere { frame =>
+ frame.getClassName == "org.perl8.test.TestMore" &&
+ frame.getMethodName == "hideTestMethod"
+ }
+ val caller = idx match {
+ case -1 => stack.headOption
+ // one level to jump out of hideTestMethod and one level to jump out of
+ // the method that called hideTestMethod
+ case i => stack.drop(i + 2).headOption
- if (level == 0) { idx } else { findIdx(level - 1, idx + 1) }
}
- val idx = findIdx(level, 0)
- val caller = stack.drop(idx).headOption
val (file, line) = caller match {
case Some(frame) => (frame.getFileName, frame.getLineNumber)
case None => ("<unknown file>", "<unknown line>")
@@ -149,20 +169,13 @@ class TestMore (plan: Option[Plan] = None) extends Test with DelayedInit {
builder.diag(message + trace)
}
- def withLevel[T] (newLevel: Int)(body: => T): T = {
- val oldLevel = level
- try {
- // XXX "+4" is something of a hack, not sure how stable it will be
- level += newLevel + 4
- body
- }
- finally {
- level = oldLevel
- }
+ // this just adds a method call with a known name to the stack trace, so
+ // that we can detect it later
+ def hideTestMethod[T] (body: => T): T = {
+ body
}
- private var level: Int = _
- private var todo: Message = _
- private var builder: TestBuilder = _
- private var testBody: () => Unit = _
+ private var todo: Message = _
+ private var builder: TestBuilder = _
+ private var testBody: () => Unit = _
}
diff --git a/src/test/scala/org/perl8/test/ExtensionTest.scala b/src/test/scala/org/perl8/test/ExtensionTest.scala
index bf1c17f..5a9c1ac 100644
--- a/src/test/scala/org/perl8/test/ExtensionTest.scala
+++ b/src/test/scala/org/perl8/test/ExtensionTest.scala
@@ -5,18 +5,14 @@ import java.io.ByteArrayOutputStream
import org.perl8.test.tap.Consumer
trait NumberZero { this: TestMore =>
- def is_zero (i: Int, desc: String): Boolean = {
- withLevel(1) {
- is(i, 0, desc)
- }
+ def is_zero (i: Int, desc: String): Boolean = hideTestMethod {
+ is(i, 0, desc)
}
}
trait NumberZeroWrapped extends NumberZero { this: TestMore =>
- def isZero (i: Int): Boolean = {
- withLevel(1) {
- is_zero(i, "the number is zero")
- }
+ def isZero (i: Int): Boolean = hideTestMethod {
+ is_zero(i, "the number is zero")
}
}