From 6f4f0015aa32de0e2eda11bfa11144961fd70480 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Thu, 28 Feb 2013 02:47:37 -0600 Subject: eliminate Message --- src/main/scala/org/perl8/test/TestMore.scala | 217 +++++++++++++-------- src/main/scala/org/perl8/test/package.scala | 24 +-- src/main/scala/org/perl8/test/tap/Producer.scala | 63 +++--- .../scala/org/perl8/test/tap/TestBuilder.scala | 75 ++++--- src/test/scala/org/perl8/test/TestMoreTest.scala | 6 +- .../scala/org/perl8/test/tap/TestBuilderTest.scala | 14 +- 6 files changed, 223 insertions(+), 176 deletions(-) (limited to 'src') diff --git a/src/main/scala/org/perl8/test/TestMore.scala b/src/main/scala/org/perl8/test/TestMore.scala index 98962b0..21ef449 100644 --- a/src/main/scala/org/perl8/test/TestMore.scala +++ b/src/main/scala/org/perl8/test/TestMore.scala @@ -7,7 +7,7 @@ import org.perl8.test.tap.TestBuilder class TestMore (plan: Plan = NoPlan) extends Test with DelayedInit { def delayedInit (body: => Unit) { testBody = { terminalInUse => - todo = NoMessage + todo = None builder = new TestBuilder(plan, terminalInUse) body } @@ -23,80 +23,64 @@ class TestMore (plan: Plan = NoPlan) extends Test with DelayedInit { builder.exitCode } - def ok (cond: Boolean, desc: Message = NoMessage): Boolean = { - builderOk(cond, desc) - if (!cond) { - failed(desc) - } - cond - } + def ok (cond: Boolean): Boolean = + test(cond) - def is[T] (got: T, expected: T, desc: Message = NoMessage): Boolean = { - val cond = got == expected - builderOk(cond, desc) - if (!cond) { - val reason = - " got: '" + got + "'\n" + - " expected: '" + expected + "'\n" - failed(desc, reason) - } - cond - } + def ok (cond: Boolean, desc: String): Boolean = + testWithDesc(cond, desc) - def isnt[T] (got: T, expected: T, desc: Message = NoMessage): Boolean = { - val cond = got != expected - builderOk(cond, desc) - if (!cond) { - val reason = - " got: '" + got + "'\n" + - " expected: anything else\n" - failed(desc, reason) - } - cond - } + def is[T] (got: T, expected: T): Boolean = + test(got == expected, isMessage(got, expected)) - def like (got: String, rx: Regex, desc: Message = NoMessage): Boolean = { - val cond = rx.findFirstIn(got).nonEmpty - builderOk(cond, desc) - if (!cond) { - val reason = - " '" + got + "'\n" + - " doesn't match '" + rx + "'\n" - failed(desc, reason) - } - cond - } + def is[T] (got: T, expected: T, desc: String): Boolean = + testWithDesc(got == expected, desc, isMessage(got, expected)) - def unlike (got: String, rx: Regex, desc: Message = NoMessage): Boolean = { - val cond = rx.findFirstIn(got).isEmpty - builderOk(cond, desc) - if (!cond) { - val reason = - " '" + got + "'\n" + - " matches '" + rx + "'\n" - failed(desc, reason) - } - cond - } + def isnt[T] (got: T, expected: T): Boolean = + test(got != expected, isntMessage(got)) + + def isnt[T] (got: T, expected: T, desc: String): Boolean = + testWithDesc(got != expected, desc, isntMessage(got)) + + def like (got: String, rx: Regex): Boolean = + test(rx.findFirstIn(got).nonEmpty, likeMessage(got, rx)) - def pass (desc: Message = NoMessage): Boolean = + def like (got: String, rx: Regex, desc: String): Boolean = + testWithDesc(rx.findFirstIn(got).nonEmpty, desc, likeMessage(got, rx)) + + def unlike (got: String, rx: Regex): Boolean = + test(rx.findFirstIn(got).isEmpty, unlikeMessage(got, rx)) + + def unlike (got: String, rx: Regex, desc: String): Boolean = + testWithDesc(rx.findFirstIn(got).isEmpty, desc, unlikeMessage(got, rx)) + + def pass: Boolean = + ok(true) + + def pass (desc: String): Boolean = ok(true, desc) - def fail (desc: Message = NoMessage): Boolean = + def fail: Boolean = + ok(false) + + def fail (desc: String): Boolean = ok(false, desc) def diag (message: String) { builder.diag(message) } - def BAIL_OUT (desc: Message = NoMessage) { + def BAIL_OUT { + builder.bailOut + } + + def BAIL_OUT (desc: String) { builder.bailOut(desc) } - def todo (reason: Message = NoMessage)(body: => Unit) { + def todo (reason: String)(body: => Unit) { val oldTodo = todo try { - todo = reason + todo = Some(reason) body } finally { @@ -104,14 +88,20 @@ class TestMore (plan: Plan = NoPlan) extends Test with DelayedInit { } } - def skip (count: Int, reason: Message = NoMessage)(body: => Unit) { + def skip (count: Int)(body: => Unit) { + for (i <- 1 to count) { + builder.skip + } + } + + def skip (count: Int, reason: String)(body: => Unit) { for (i <- 1 to count) { builder.skip(reason) } } def subtest ( - name: Message, + name: String, plan: Plan = NoPlan )(body: => Unit): Boolean = { val oldBuilder = builder @@ -126,32 +116,74 @@ class TestMore (plan: Plan = NoPlan) extends Test with DelayedInit { ok(success, name) } - protected def ignoreFrame (frame: StackTraceElement): Boolean = { - val className = frame.getClassName - val methodName = frame.getMethodName + private def isMessage[T] (got: T, expected: T): String = + " got: '" + got + "'\n" + + " expected: '" + expected + "'\n" - // 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 isntMessage[T] (got: T): String = + " got: '" + got + "'\n" + + " expected: anything else\n" + + private def likeMessage (got: String, rx: Regex): String = + " '" + got + "'\n" + + " doesn't match '" + rx + "'\n" + + private def unlikeMessage (got: String, rx: Regex): String = + " '" + got + "'\n" + + " matches '" + rx + "'\n" + + private def testWithDesc ( + cond: Boolean, + desc: String + ): Boolean = { + todo match { + case Some(t) => builder.okTodo(cond, "- " + desc, t) + case None => builder.ok(cond, "- " + desc) + } + if (!cond) { + failed(Some(desc), None) + } + cond } - private def builderOk (cond: Boolean, desc: Message) { - builder.ok(cond, desc.map(d => "- " + d), todo) + private def testWithDesc ( + cond: Boolean, + desc: String, + reason: => String + ): Boolean = { + todo match { + case Some(t) => builder.okTodo(cond, "- " + desc, t) + case None => builder.ok(cond, "- " + desc) + } + if (!cond) { + failed(Some(desc), Some(reason)) + } + cond + } + + private def test (cond: Boolean): Boolean = { + todo match { + case Some(t) => builder.okTodo(cond, t) + case None => builder.ok(cond) + } + if (!cond) { + failed(None, None) + } + cond } - private def failed (desc: Message, reason: String) { - failed(desc, Some(reason)) + private def test (cond: Boolean, reason: => String): Boolean = { + todo match { + case Some(t) => builder.okTodo(cond, t) + case None => builder.ok(cond) + } + if (!cond) { + failed(None, Some(reason)) + } + cond } - private def failed (desc: Message, reason: Option[String] = None) { + private def failed (desc: Option[String], reason: Option[String]) { val stack = Thread.currentThread.getStackTrace.drop(1).filter { frame => !ignoreFrame(frame) } @@ -171,11 +203,11 @@ class TestMore (plan: Plan = NoPlan) extends Test with DelayedInit { case None => ("", "") } val message = " " + (todo match { - case HasMessage(_) => "Failed (TODO) test" - case NoMessage => "Failed test" + case Some(_) => "Failed (TODO) test" + case None => "Failed test" }) + (desc match { - case HasMessage(m) => " '" + m + "'\n " - case NoMessage => " " + case Some(m) => " '" + m + "'\n " + case None => " " }) val trace = "at " + file + " line " + line + "." builder.diag(message + trace + reason.map("\n" + _).getOrElse("")) @@ -187,7 +219,24 @@ class TestMore (plan: Plan = NoPlan) extends Test with DelayedInit { body } - private var todo: Message = _ - private var builder: TestBuilder = _ + 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 var todo: Option[String] = _ + private var builder: TestBuilder = _ private var testBody: Boolean => Unit = _ } diff --git a/src/main/scala/org/perl8/test/package.scala b/src/main/scala/org/perl8/test/package.scala index 5d7ba32..b18dc2f 100644 --- a/src/main/scala/org/perl8/test/package.scala +++ b/src/main/scala/org/perl8/test/package.scala @@ -6,9 +6,6 @@ package object test { implicit def intToPlan (p: Int): Plan = NumericPlan(p) - implicit def stringToMessage (s: String): Message = - new HasMessage(s) - sealed trait Plan { val plan: Int val skipAll: Boolean @@ -42,22 +39,7 @@ package object test { def apply () = SkipAllNoMessage } - sealed trait Message - case class HasMessage (contents: String) extends Message - case object NoMessage extends Message - - implicit def messageToOption (message: Message): Option[String] = - message match { - case HasMessage(x) => Some(x) - case NoMessage => None - } - - implicit def optionToMessage (option: Option[String]): Message = - option match { - case Some(x) => HasMessage(x) - case None => NoMessage - } - - case class BailOutException (message: String) - extends RuntimeException(message) + case class BailOutException ( + message: String + ) extends RuntimeException(message) } diff --git a/src/main/scala/org/perl8/test/tap/Producer.scala b/src/main/scala/org/perl8/test/tap/Producer.scala index 4b45970..52c72c9 100644 --- a/src/main/scala/org/perl8/test/tap/Producer.scala +++ b/src/main/scala/org/perl8/test/tap/Producer.scala @@ -3,42 +3,39 @@ package org.perl8.test.tap object Producer { import org.perl8.test._ - def result ( - cond: Boolean, - num: Int, - desc: Message = NoMessage, - todo: Message = NoMessage - ): String = - join( - (if (!cond) Some("not") else None), - Some("ok"), - Some(num), - desc, - todo.map(t => "# TODO " + t) - ) - - def skip (num: Int, reason: Message = NoMessage): String = - join( - Some("ok"), - Some(num), - Some("# skip"), - reason - ) + def result (cond: Boolean, num: Int): String = + (if (cond) "ok " else "not ok ") + num + + def result (cond: Boolean, num: Int, desc: String): String = + result(cond, num) + " " + desc + + def todoResult (cond: Boolean, num: Int, todo: String): String = + result(cond, num) + " # TODO " + todo + + def todoResult (cond: Boolean, num: Int, desc: String, todo: String): String = + result(cond, num, desc) + " # TODO " + todo + + def skip (num: Int): String = + "ok " + num + " # skip" + + def skip (num: Int, reason: String): String = + skip(num) + " " + reason def comment (message: String): String = message.split("\n").map(m => "# " + m).mkString("\n") def plan (plan: Plan): String = - join( - Some("1.." + plan.plan), - (if (plan.skipAll || plan.message.isDefined) Some("#") else None), - (if (plan.skipAll) Some("SKIP") else None), - plan.message - ) - - def bailOut (message: Message = NoMessage) = - join(Some("Bail out!"), message) - - private def join (strings: Option[Any]*): String = - strings.flatMap(x => x).mkString(" ") + if (plan.skipAll) { + val skip = "1..0 # SKIP" + plan.message.map(m => skip + " " + m).getOrElse(skip) + } + else { + "1.." + plan.plan + } + + def bailOut: String = + "Bail out!" + + def bailOut (message: String): String = + "Bail out! " + message } diff --git a/src/main/scala/org/perl8/test/tap/TestBuilder.scala b/src/main/scala/org/perl8/test/tap/TestBuilder.scala index 432f902..99465fd 100644 --- a/src/main/scala/org/perl8/test/tap/TestBuilder.scala +++ b/src/main/scala/org/perl8/test/tap/TestBuilder.scala @@ -18,55 +18,74 @@ class TestBuilder private ( def cloneForSubtest (newPlan: Plan): TestBuilder = new TestBuilder(newPlan, indent + " ", terminalInUse) - def ok ( - test: Boolean, - description: Message = NoMessage, - todo: Message = NoMessage - ) { - val line = Producer.result(test, state.currentTest, description, todo) - state.ok(test || todo.isDefined) - outLine(line) + def ok (test: Boolean) { + state.ok(test) + outLine(Producer.result(test, state.currentTest)) } - def skip (reason: Message = NoMessage) { - val line = Producer.skip(state.currentTest, reason) + def ok (test: Boolean, description: String) { + state.ok(test) + outLine(Producer.result(test, state.currentTest, description)) + } + + def okTodo (test: Boolean, todo: String) { state.ok(true) - outLine(line) + outLine(Producer.todoResult(test, state.currentTest, todo)) } - def diag (message: Message) { - message.foreach { m => - errLine(Producer.comment(m)) - } + def okTodo (test: Boolean, description: String, todo: String) { + state.ok(true) + outLine(Producer.todoResult(test, state.currentTest, description, todo)) + } + + def skip { + state.ok(true) + outLine(Producer.skip(state.currentTest)) + } + + def skip (reason: String) { + state.ok(true) + outLine(Producer.skip(state.currentTest, reason)) + } + + def diag (message: String) { + errLine(Producer.comment(message)) + } + + def note (message: String) { + outLine(Producer.comment(message)) } - def note (message: Message) { - message.foreach(m => outLine(Producer.comment(m))) + def bailOut { + val bailOutMessage = Producer.bailOut + outLine(bailOutMessage) + throw new BailOutException(bailOutMessage) } - def bailOut (message: Message = NoMessage) { - outLine(Producer.bailOut(message)) - throw new BailOutException(message.getOrElse("")) + def bailOut (message: String) { + val bailOutMessage = Producer.bailOut(message) + outLine(bailOutMessage) + throw new BailOutException(bailOutMessage) } def doneTesting: Boolean = { plan match { - case NoPlan => outLine(Producer.plan(state.currentTest - 1)) + case NoPlan => outLine(Producer.plan(state.currentTest)) case _ => () } if (!state.isPassing) { if (!state.matchesPlan) { val planCount = (plan match { - case NoPlan => state.currentTest - 1 + case NoPlan => state.currentTest case p => p.plan }) val planned = planCount + " test" + (if (planCount > 1) "s" else "") - val ran = state.currentTest - 1 + val ran = state.currentTest diag("Looks like you planned " + planned + " but ran " + ran + ".") } - if (state.currentTest == 1) { + if (state.currentTest == 0) { diag("No tests run!") } @@ -74,7 +93,7 @@ class TestBuilder private ( val count = state.failCount val fails = count + " test" + (if (count > 1) "s" else "") val total = - state.currentTest - 1 + (if (state.matchesPlan) "" else " run") + state.currentTest + (if (state.matchesPlan) "" else " run") diag("Looks like you failed " + fails + " of " + total + ".") } } @@ -126,14 +145,14 @@ class TestBuilder private ( } def currentTest: Int = - failCount + passCount + 1 + failCount + passCount def matchesPlan: Boolean = plan match { - case NumericPlan(p) => p.plan == failCount + passCount + case NumericPlan(p) => p.plan == currentTest case _ => true } def isPassing: Boolean = - currentTest > 1 && failCount == 0 && matchesPlan + currentTest > 0 && failCount == 0 && matchesPlan } } diff --git a/src/test/scala/org/perl8/test/TestMoreTest.scala b/src/test/scala/org/perl8/test/TestMoreTest.scala index 8555a71..317aaaf 100644 --- a/src/test/scala/org/perl8/test/TestMoreTest.scala +++ b/src/test/scala/org/perl8/test/TestMoreTest.scala @@ -43,17 +43,17 @@ class TestMoreTest extends TestMore { diag("pass") pass("it works!") - pass() + pass skip(2, "don't do this yet") { pass("skipped") - pass() + pass } todo("not working yet") { diag("fail") fail("it doesn't work") - fail() + fail } } diff --git a/src/test/scala/org/perl8/test/tap/TestBuilderTest.scala b/src/test/scala/org/perl8/test/tap/TestBuilderTest.scala index 6aff4a1..d59541a 100644 --- a/src/test/scala/org/perl8/test/tap/TestBuilderTest.scala +++ b/src/test/scala/org/perl8/test/tap/TestBuilderTest.scala @@ -160,19 +160,19 @@ class TestBuilderTest extends TestMore { builder.bailOut("oh no!") Console.withOut(oldOut) { Console.withErr(oldErr) { - fail() + fail } } } catch { case e: BailOutException => Console.withOut(oldOut) { Console.withErr(oldErr) { - is(e.message, "oh no!") + is(e.message, "Bail out! oh no!") } } case _: Throwable => Console.withOut(oldOut) { Console.withErr(oldErr) { - fail() + fail } } } @@ -181,7 +181,7 @@ class TestBuilderTest extends TestMore { val expected = "ok 1\n" + - "Bail out! oh no!\n" + "Bail out! oh no!\n" is(output.toString, expected) } @@ -221,7 +221,7 @@ class TestBuilderTest extends TestMore { val builder = new TestBuilder builder.ok(false) builder.skip("not now") - builder.skip() + builder.skip builder.doneTesting } } @@ -241,8 +241,8 @@ class TestBuilderTest extends TestMore { Console.withOut(output) { Console.withErr(output) { val builder = new TestBuilder - builder.ok(false, "do a thing", todo = "not working yet") - builder.ok(true, todo = "is it?") + builder.okTodo(false, "do a thing", todo = "not working yet") + builder.okTodo(true, todo = "is it?") builder.doneTesting } } -- cgit v1.2.3-54-g00ecf