Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2001-2008 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.tools
import org.scalatest._
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.OutputStream
import java.io.OutputStreamWriter
import java.io.PrintWriter
import java.util.Iterator
import java.util.Set
import java.io.StringWriter
import org.scalatest.events._
import org.scalatest.exceptions.TestFailedException
import PrintReporter.{BufferSize, makeDurationString}
import HtmlReporter._
import org.pegdown.PegDownProcessor
import scala.collection.mutable.ListBuffer
import scala.xml.NodeSeq
import scala.xml.XML
import java.util.UUID
import scala.xml.Node
import scala.annotation.tailrec
import java.net.URL
import scala.io.Source
import java.nio.channels.Channels
import java.text.DecimalFormat
/**
* A Reporter that prints test status information in HTML format to a file.
*/
private[scalatest] class HtmlReporter(directoryPath: String, presentAllDurations: Boolean,
presentInColor: Boolean, presentStackTraces: Boolean, presentFullStackTraces: Boolean,
cssUrl: Option[URL], resultHolder: Option[SuiteResultHolder]) extends ResourcefulReporter {
private val specIndent = 15
private val targetDir = new File(directoryPath)
private val imagesDir = new File(targetDir, "images")
private val jsDir = new File(targetDir, "js")
private val cssDir = new File(targetDir, "css")
if (!targetDir.exists)
targetDir.mkdirs()
if (!imagesDir.exists)
imagesDir.mkdirs()
if (!jsDir.exists)
jsDir.mkdirs()
if (!cssDir.exists)
cssDir.mkdirs()
private def copyResource(url: URL, toDir: File, targetFileName: String) {
val inputStream = url.openStream
try {
val outputStream = new FileOutputStream(new File(toDir, targetFileName))
try {
outputStream getChannel() transferFrom(Channels.newChannel(inputStream), 0, Long.MaxValue)
}
finally {
outputStream.flush()
outputStream.close()
}
}
finally {
inputStream.close()
}
}
private def getResource(resourceName: String): URL =
classOf[Suite].getClassLoader.getResource(resourceName)
cssUrl match {
case Some(cssUrl) => copyResource(cssUrl, cssDir, "custom.css")
case None => // Do nothing.
}
copyResource(getResource("org/scalatest/HtmlReporter.css"), cssDir, "styles.css")
copyResource(getResource("org/scalatest/sorttable.js"), jsDir, "sorttable.js")
copyResource(getResource("org/scalatest/d3.v2.min.js"), jsDir, "d3.v2.min.js")
copyResource(getResource("images/greenbullet.gif"), imagesDir, "testsucceeded.gif")
copyResource(getResource("images/redbullet.gif"), imagesDir, "testfailed.gif")
copyResource(getResource("images/yellowbullet.gif"), imagesDir, "testignored.gif")
copyResource(getResource("images/yellowbullet.gif"), imagesDir, "testcanceled.gif")
copyResource(getResource("images/yellowbullet.gif"), imagesDir, "testpending.gif")
copyResource(getResource("images/graybullet.gif"), imagesDir, "infoprovided.gif")
private val results = resultHolder match {
case Some(holder) => holder
case None => new SuiteResultHolder()
}
private val pegDown = new PegDownProcessor
private def withPossibleLineNumber(stringToPrint: String, throwable: Option[Throwable]): String = {
throwable match {
case Some(testFailedException: TestFailedException) =>
testFailedException.failedCodeFileNameAndLineNumberString match {
case Some(lineNumberString) =>
Resources("printedReportPlusLineNumber", stringToPrint, lineNumberString)
case None => stringToPrint
}
case _ => stringToPrint
}
}
private def stringsToPrintOnError(noteResourceName: String, errorResourceName: String, message: String, throwable: Option[Throwable],
formatter: Option[Formatter], suiteName: Option[String], testName: Option[String], duration: Option[Long]): String = {
formatter match {
case Some(IndentedText(_, rawText, _)) =>
Resources("specTextAndNote", rawText, Resources(noteResourceName))
case _ =>
// Deny MotionToSuppress directives in error events, because error info needs to be seen by users
suiteName match {
case Some(sn) =>
testName match {
case Some(tn) => Resources(errorResourceName, sn + ": " + tn)
case None => Resources(errorResourceName, sn)
}
// Should not get here with built-in ScalaTest stuff, but custom stuff could get here.
case None => Resources(errorResourceName, Resources("noNameSpecified"))
}
}
}
private def stringToPrintWhenNoError(resourceName: String, formatter: Option[Formatter], suiteName: String, testName: Option[String]): Option[String] =
stringToPrintWhenNoError(resourceName, formatter, suiteName, testName, None)
private def stringToPrintWhenNoError(resourceName: String, formatter: Option[Formatter], suiteName: String, testName: Option[String], duration: Option[Long]): Option[String] = {
formatter match {
case Some(IndentedText(_, rawText, _)) =>
duration match {
case Some(milliseconds) =>
if (presentAllDurations)
Some(Resources("withDuration", rawText, makeDurationString(milliseconds)))
else
Some(rawText)
case None => Some(rawText)
}
case Some(MotionToSuppress) => None
case _ =>
val arg =
testName match {
case Some(tn) => suiteName + ": " + tn
case None => suiteName
}
val unformattedText = Resources(resourceName, arg)
duration match {
case Some(milliseconds) =>
if (presentAllDurations)
Some(Resources("withDuration", unformattedText, makeDurationString(milliseconds)))
else
Some(unformattedText)
case None => Some(unformattedText)
}
}
}
private def getIndentLevel(formatter: Option[Formatter]) =
formatter match {
case Some(IndentedText(formattedText, rawText, indentationLevel)) => indentationLevel
case _ => 0
}
private def getSuiteFileName(suiteResult: SuiteResult) =
suiteResult.suiteClassName match {
case Some(suiteClassName) => suiteClassName
case None => suiteResult.suiteName
}
private def makeSuiteFile(suiteResult: SuiteResult) {
val name = getSuiteFileName(suiteResult)
val pw = new PrintWriter(new BufferedOutputStream(new FileOutputStream(new File(targetDir, name + ".html")), BufferSize))
try {
pw.println {
"" + "\n" +
"" + "\n" +
getSuiteHtml(name, suiteResult)
}
}
finally {
pw.flush()
pw.close()
}
}
private def appendCombinedStatus(name: String, r: SuiteResult) =
if (r.testsFailedCount > 0)
name + "_with_failed"
else if (r.testsIgnoredCount > 0 || r.testsPendingCount > 0 || r.testsCanceledCount > 0)
name + "_passed"
else
name + "_passed_all"
private def transformStringForResult(s: String, suiteResult: SuiteResult): String =
s + (if (suiteResult.testsFailedCount > 0) "_failed" else "_passed")
private def getSuiteHtml(name: String, suiteResult: SuiteResult) =
ScalaTest Suite { name } Results
{
cssUrl match {
case Some(cssUrl) =>
case None => NodeSeq.Empty
}
}
}
private def twoLess(indentLevel: Int): Int =
indentLevel - 2 match {
case lev if lev < 0 => 0
case lev => lev
}
private def oneLess(indentLevel: Int): Int =
indentLevel - 1 match {
case lev if lev < 0 => 0
case lev => lev
}
private def scope(elementId: String, message: String, indentLevel: Int) =
&+ getHTMLForCause(cause)
}
else new scala.xml.NodeBuffer
}
val (grayStackTraceElements, blackStackTraceElements) =
throwable match {
case Some(throwable) =>
val stackTraceElements = throwable.getStackTrace.toList
throwable match {
case sde: exceptions.StackDepthException =>
(stackTraceElements.take(sde.failedCodeStackDepth), stackTraceElements.drop(sde.failedCodeStackDepth))
case _ => (List(), stackTraceElements)
}
case None => (List(), List())
}
val throwableTitle =
throwable match {
case Some(throwable) => Some(throwable.getClass.getName)
case None => None
}
val fileAndLineOption: Option[String] =
throwable match {
case Some(throwable) =>
throwable match {
case stackDepth: StackDepth =>
stackDepth.failedCodeFileNameAndLineNumberString
case _ => None
}
case None => None
}
val linkId = UUID.randomUUID.toString
val contentId = UUID.randomUUID.toString
{
// Put 's in for line returns at least, so property check failure messages look better
val messageLines = message.split("\n")
if (messageLines.size > 1)
messageLines.map(line => { line } )
else
{ message }
}
//}
//else
}
{
fileAndLineOption match {
case Some(fileAndLine) =>
{ Resources("LineNumber") + ":" }
{ "(" + fileAndLine + ")" }
case None =>
}
}
{
throwableTitle match {
case Some(title) =>
private def tagMapScript =
"tagMap = { \n" +
tagMap.map { case (elementId, bitSet) => "\"" + elementId + "\": " + bitSet }.mkString(", \n") +
"};\n" +
"applyFilter();"
private var eventList = new ListBuffer[Event]()
private var runEndEvent: Option[Event] = None
def apply(event: Event) {
event match {
case RunStarting(ordinal, testCount, configMap, formatter, location, payload, threadName, timeStamp) =>
case RunCompleted(ordinal, duration, summary, formatter, location, payload, threadName, timeStamp) =>
runEndEvent = Some(event)
case RunStopped(ordinal, duration, summary, formatter, location, payload, threadName, timeStamp) =>
runEndEvent = Some(event)
case RunAborted(ordinal, message, throwable, duration, summary, formatter, location, payload, threadName, timeStamp) =>
runEndEvent = Some(event)
case SuiteCompleted(ordinal, suiteName, suiteId, suiteClassName, duration, formatter, location, rerunner, payload, threadName, timeStamp) =>
val (suiteEvents, otherEvents) = extractSuiteEvents(suiteId)
eventList = otherEvents
val sortedSuiteEvents = suiteEvents.sorted
if (sortedSuiteEvents.length == 0)
throw new IllegalStateException("Expected SuiteStarting for completion event: " + event + " in the head of suite events, but we got no suite event at all")
sortedSuiteEvents.head match {
case suiteStarting: SuiteStarting =>
val suiteResult = sortedSuiteEvents.foldLeft(SuiteResult(suiteId, suiteName, suiteClassName, duration, suiteStarting, event, Vector.empty ++ sortedSuiteEvents.tail, 0, 0, 0, 0, 0, true)) { case (r, e) =>
e match {
case testSucceeded: TestSucceeded => r.copy(testsSucceededCount = r.testsSucceededCount + 1)
case testFailed: TestFailed => r.copy(testsFailedCount = r.testsFailedCount + 1)
case testIgnored: TestIgnored => r.copy(testsIgnoredCount = r.testsIgnoredCount + 1)
case testPending: TestPending => r.copy(testsPendingCount = r.testsPendingCount + 1)
case testCanceled: TestCanceled => r.copy(testsCanceledCount = r.testsCanceledCount + 1)
case _ => r
}
}
results += suiteResult
makeSuiteFile(suiteResult)
case other =>
throw new IllegalStateException("Expected SuiteStarting for completion event: " + event + " in the head of suite events, but we got: " + other)
}
case SuiteAborted(ordinal, message, suiteName, suiteId, suiteClassName, throwable, duration, formatter, location, rerunner, payload, threadName, timeStamp) =>
val (suiteEvents, otherEvents) = extractSuiteEvents(suiteId)
eventList = otherEvents
val sortedSuiteEvents = suiteEvents.sorted
if (sortedSuiteEvents.length == 0)
throw new IllegalStateException("Expected SuiteStarting for completion event: " + event + " in the head of suite events, but we got no suite event at all")
sortedSuiteEvents.head match {
case suiteStarting: SuiteStarting =>
val suiteResult = sortedSuiteEvents.foldLeft(SuiteResult(suiteId, suiteName, suiteClassName, duration, suiteStarting, event, Vector.empty ++ sortedSuiteEvents.tail, 0, 0, 0, 0, 0, false)) { case (r, e) =>
e match {
case testSucceeded: TestSucceeded => r.copy(testsSucceededCount = r.testsSucceededCount + 1)
case testFailed: TestFailed => r.copy(testsFailedCount = r.testsFailedCount + 1)
case testIgnored: TestIgnored => r.copy(testsIgnoredCount = r.testsIgnoredCount + 1)
case testPending: TestPending => r.copy(testsPendingCount = r.testsPendingCount + 1)
case testCanceled: TestCanceled => r.copy(testsCanceledCount = r.testsCanceledCount + 1)
case _ => r
}
}
results += suiteResult
makeSuiteFile(suiteResult)
case other =>
throw new IllegalStateException("Expected SuiteStarting for completion event: " + event + " in the head of suite events, but we got: " + other)
}
case _ => eventList += event
}
}
def extractSuiteEvents(suiteId: String) = eventList partition { e =>
e match {
case e: TestStarting => e.suiteId == suiteId
case e: TestSucceeded => e.suiteId == suiteId
case e: TestIgnored => e.suiteId == suiteId
case e: TestFailed => e.suiteId == suiteId
case e: TestPending => e.suiteId == suiteId
case e: TestCanceled => e.suiteId == suiteId
case e: InfoProvided =>
e.nameInfo match {
case Some(nameInfo) =>
nameInfo.suiteId == suiteId
case None => false
}
case e: MarkupProvided =>
e.nameInfo match {
case Some(nameInfo) =>
nameInfo.suiteId == suiteId
case None => false
}
case e: ScopeOpened => e.nameInfo.suiteId == suiteId
case e: ScopeClosed => e.nameInfo.suiteId == suiteId
case e: SuiteStarting => e.suiteId == suiteId
case _ => false
}
}
def dispose() {
runEndEvent match {
case Some(event) =>
event match {
case RunCompleted(ordinal, duration, summary, formatter, location, payload, threadName, timeStamp) =>
makeIndexFile("runCompleted", duration)
case RunStopped(ordinal, duration, summary, formatter, location, payload, threadName, timeStamp) =>
makeIndexFile("runStopped", duration)
case RunAborted(ordinal, message, throwable, duration, summary, formatter, location, payload, threadName, timeStamp) =>
makeIndexFile("runAborted", duration)
case other =>
throw new IllegalStateException("Expected run ending event only, but got: " + other.getClass.getName)
}
case None => // If no run end event (e.g. when run in sbt), just use runCompleted with sum of suites' duration.
makeIndexFile("runCompleted", Some(results.totalDuration))
}
}
private def getDuration(resourceName: String, duration: Option[Long]) = {
duration match {
case Some(msSinceEpoch) =>
Resources(resourceName + "In", makeDurationString(msSinceEpoch))
case None =>
Resources(resourceName)
}
}
private def getTotalTests(summary: Summary) =
Resources("totalNumberOfTestsRun", summary.testsCompletedCount.toString)
// Suites: completed {0}, aborted {1}
private def getSuiteSummary(summary: Summary) =
Resources("suiteSummary", summary.suitesCompletedCount.toString, summary.suitesAbortedCount.toString)
// Tests: succeeded {0}, failed {1}, canceled {4}, ignored {2}, pending {3}
private def getTestSummary(summary: Summary) =
Resources("testSummary", summary.testsSucceededCount.toString, summary.testsFailedCount.toString, summary.testsCanceledCount.toString, summary.testsIgnoredCount.toString,
summary.testsPendingCount.toString)
// We subtract one from test reports because we add "- " in front, so if one is actually zero, it will come here as -1
// private def indent(s: String, times: Int) = if (times <= 0) s else (" " * times) + s
// Stupid properties file won't let me put spaces at the beginning of a property
// " {0}" comes out as "{0}", so I can't do indenting in a localizable way. For now
// just indent two space to the left. // if (times <= 0) s
// else Resources("indentOnce", indent(s, times - 1))
}
private[tools] object HtmlReporter {
final val SUCCEEDED_BIT = 1
final val FAILED_BIT = 2
final val IGNORED_BIT = 4
final val PENDING_BIT = 8
final val CANCELED_BIT = 16
}
private[tools] object PCDATA {
def apply(in: String): Node = scala.xml.Unparsed(in)
}