All Downloads are FREE. Search and download functionalities are using the official Maven repository.

minitest.api.Result.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2014-2019 by The Minitest Project Developers.
 * Some rights reserved.
 *
 * 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 minitest.api

import scala.compat.Platform.EOL
import scala.Console.{GREEN, RED, YELLOW, RESET}

sealed trait Result[+T] {
  def formatted(name: String, withColors: Boolean): String
}

object Result {
  final case class Success[+T](value: T) extends Result[T] {
    def formatted(name: String, withColors: Boolean): String = {
      val color = if (withColors) GREEN else ""
      val reset = if (withColors) RESET else ""
      color + "- " + name + reset + EOL
    }
  }

  final case class Ignored(reason: Option[String], location: Option[SourceLocation])
    extends Result[Nothing] {

    def formatted(name: String, withColors: Boolean): String = {
      val color = if (withColors) YELLOW else ""
      val reset = if (withColors) RESET else ""
      val reasonStr = reason.fold("")(msg => formatDescription(msg, location, color, reset, "  "))
      color + "- " + name + " !!! IGNORED !!!" + reset + EOL + reasonStr
    }
  }

  final case class Canceled(reason: Option[String], location: Option[SourceLocation])
    extends Result[Nothing] {

    def formatted(name: String, withColors: Boolean): String = {
      val color = if (withColors) YELLOW else ""
      val reset = if (withColors) RESET else ""
      val reasonStr = reason.fold("")(msg => formatDescription(msg, location, color, reset, "  "))
      color + "- " + name + " !!! CANCELED !!!" + reset + EOL + reasonStr
    }
  }

  final case class Failure(msg: String, source: Option[Throwable], location: Option[SourceLocation])
    extends Result[Nothing] {

    def formatted(name: String, withColors: Boolean): String =
      formatError(name, msg, source, location, Some(20), withColors)
  }

  final case class Exception(source: Throwable, location: Option[SourceLocation])
    extends Result[Nothing] {

    def formatted(name: String, withColors: Boolean): String = {
      val description = {
        val name = source.getClass.getName
        val className = name.substring(name.lastIndexOf(".") + 1)
        Option(source.getMessage).filterNot(_.isEmpty)
          .fold(className)(m => s"$className: $m")
      }

      formatError(name, description, Some(source), location, None, withColors)
    }
  }

  def from(error: Throwable): Result[Nothing] = error match {
    case ex: AssertionException =>
      Result.Failure(ex.message, Some(ex), Some(ex.location))
    case ex: UnexpectedException =>
      Result.Exception(ex.reason, Some(ex.location))
    case ex: InterceptException =>
      Result.Exception(ex, Some(ex.location))
    case ex: IgnoredException =>
      Result.Ignored(ex.reason, ex.location)
    case ex: CanceledException =>
      Result.Canceled(ex.reason, ex.location)
    case other =>
      Result.Exception(other, None)
  }

  private def formatError(name: String, msg: String,
    source: Option[Throwable],
    location: Option[SourceLocation],
    traceLimit: Option[Int],
    withColors: Boolean): String = {

    val color = if (withColors) RED else ""
    val reset = if (withColors) RESET else ""
    val stackTrace = source.fold("") { ex =>
      val trace: Array[String] = {
        val tr = ex.getStackTrace.map(_.toString)
        traceLimit.fold(tr) { limit =>
          if (tr.length <= limit) tr else
            tr.take(limit) :+ "..."
        }
      }

      formatDescription(trace.mkString("\n"), None, color, reset, "    ")
    }

    val formattedMessage = formatDescription(
      if (msg != null && msg.nonEmpty) msg else "Test failed",
      location, color, reset, "  ")

    color + s"- $name *** FAILED ***" + reset + EOL +
      formattedMessage + stackTrace
  }

  private def formatDescription(
    message: String,
    location: Option[SourceLocation],
    color: String,
    reset: String,
    prefix: String): String = {

    val lines = message.split("\\r?\\n").zipWithIndex.map { case (line, index) =>
      if (index == 0)
        color + prefix + line +
          location.fold("")(l => s" (${l.fileName.getOrElse("none")}:${l.line})") +
          reset +
          EOL
      else
        color + prefix + line + reset + EOL
    }

    lines.mkString
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy