org.scalatest.Reporter.scala Maven / Gradle / Ivy
/*
* Copyright 2001-2013 Artima, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.scalatest
import org.scalatest.events.Event
/**
* Trait whose instances collect the results of a running
* suite of tests and presents those results in some way to the user. Instances of this trait can
* be called "report functions" or "reporters."
*
*
* Reporters receive test results via fifteen events.
* Each event is fired to pass a particular kind of information to
* the reporter. The events are:
*
*
*
* DiscoveryStarting
* DiscoveryCompleted
* RunStarting
* RunStopped
* RunAborted
* RunCompleted
* ScopeOpened
* ScopeClosed
* ScopePending
* TestStarting
* TestSucceeded
* TestFailed
* TestCanceled
* TestIgnored
* TestPending
* SuiteStarting
* SuiteCompleted
* SuiteAborted
* InfoProvided
* MarkupProvided
* AlertProvided
* NoteProvided
*
*
*
* Reporters may be implemented such that they only present some of the reported events to the user. For example, you could
* define a reporter class that does nothing in response to SuiteStarting events.
* Such a class would always ignore SuiteStarting events.
*
*
*
* The term test as used in the TestStarting, TestSucceeded,
* and TestFailed event names
* is defined abstractly to enable a wide range of test implementations.
* ScalaTest's style traits (subclasse of trait Suite) fire
* TestStarting to indicate they are about to invoke one
* of their tests, TestSucceeded to indicate a test returned normally,
* and TestFailed to indicate a test completed abruptly with an exception.
* Although the execution of a Suite subclass's tests will likely be a common event
* reported via the
* TestStarting, TestSucceeded, and TestFailed events, because
* of the abstract definition of “test” used by the
* the event classes, these events are not limited to this use. Information about any conceptual test
* may be reported via the TestStarting, TestSucceeded, and
* TestFailed events.
*
*
* Likewise, the term suite as used in the SuiteStarting, SuiteAborted,
* and SuiteCompleted event names
* is defined abstractly to enable a wide range of suite implementations.
* Object Runner fires SuiteStarting to indicate it is about to invoke
* run on a
* Suite, SuiteCompleted to indicate a Suite's
* run method returned normally,
* and SuiteAborted to indicate a Suite's run
* method completed abruptly with an exception.
* Similarly, class Suite fires SuiteStarting to indicate it is about to invoke
* run on a
* nested Suite, SuiteCompleted to indicate a nested Suite's
* run method returned normally,
* and SuiteAborted to indicate a nested Suite's run
* method completed abruptly with an exception.
* Although the execution of a Suite's run method will likely be a
* common event reported via the
* SuiteStarting, SuiteAborted, and SuiteCompleted events, because
* of the abstract definition of "suite" used by the
* event classes, these events are not limited to this use. Information about any conceptual suite
* may be reported via the SuiteStarting, SuiteAborted, and
* SuiteCompleted events.
*
*
Extensibility
*
*
* You can create classes that extend Reporter to report test results in custom ways, and to
* report custom information passed as an event "payload."
* Reporter classes can handle events in any manner, including doing nothing.
*
*
* @author Bill Venners
*/
trait Reporter {
/**
* Invoked to report an event that subclasses may wish to report in some way to the user.
*
* @param event the event being reported
*/
def apply(event: Event)
}
private[scalatest] object Reporter {
private[scalatest] def indentStackTrace(stackTrace: String, level: Int): String = {
val indentation = if (level > 0) " " * level else ""
val withTabsZapped = stackTrace.replaceAll("\t", " ")
val withInitialIndent = indentation + withTabsZapped
withInitialIndent.replaceAll("\n", "\n" + indentation) // I wonder if I need to worry about alternate line endings. Probably.
}
// In the unlikely event that a message is blank, use the throwable's detail message
private[scalatest] def messageOrThrowablesDetailMessage(message: String, throwable: Option[Throwable]): String = {
val trimmedMessage = message.trim
if (!trimmedMessage.isEmpty)
trimmedMessage
else
throwable match {
case Some(t) => t.getMessage.trim
case None => ""
}
}
// TODO: Not a real problem, but if a DispatchReporter ever got itself in
// its list of reporters, this would end up being an infinite loop. But
// That first part, a DispatchReporter getting itself in there would be the real
// bug.
def propagateDispose(reporter: Reporter): Unit = {
reporter match {
// SKIP-SCALATESTJS-START
case dispatchReporter: DispatchReporter => dispatchReporter.dispatchDisposeAndWaitUntilDone()
// SKIP-SCALATESTJS-END
case resourcefulReporter: ResourcefulReporter => resourcefulReporter.dispose()
case _ =>
}
}
}
/*
case RunStarting(ordinal, testCount, formatter, payload, threadName, timeStamp) => runStarting(testCount)
case TestStarting(ordinal, suiteName, suiteClassName, testName, formatter, rerunnable, payload, threadName, timeStamp) =>
case TestSucceeded(ordinal, suiteName, suiteClassName, testName, duration, formatter, rerunnable, payload, threadName, timeStamp) =>
case TestFailed(ordinal, message, suiteName, suiteClassName, testName, throwable, duration, formatter, rerunnable, payload, threadName, timeStamp) =>
case TestIgnored(ordinal, suiteName, suiteClassName, testName, formatter, payload, threadName, timeStamp) =>
case TestPending(ordinal, suiteName, suiteClassName, testName, formatter, payload, threadName, timeStamp) =>
case SuiteStarting(ordinal, suiteName, suiteClassName, formatter, rerunnable, payload, threadName, timeStamp) =>
case SuiteCompleted(ordinal, suiteName, suiteClassName, duration, formatter, rerunnable, payload, threadName, timeStamp) =>
case SuiteAborted(ordinal, message, suiteName, suiteClassName, throwable, duration, formatter, rerunnable, payload, threadName, timeStamp) =>
case InfoProvided(ordinal, message, nameInfo, throwable, formatter, payload, threadName, timeStamp) => {
case RunStopped(ordinal, duration, summary, formatter, payload, threadName, timeStamp) => runStopped()
case RunAborted(ordinal, message, throwable, duration, summary, formatter, payload, threadName, timeStamp) =>
case RunCompleted(ordinal, duration, summary, formatter, payload, threadName, timeStamp) => runCompleted()
*/