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.
package org.specs2
package reporter
import scalaz._
import Scalaz._
import Tree._
import collection.Seqx._
import specification._
import text.Trim._
import data.Trees._
import StandardFragments._
/**
* This class computes the 'level' of a given fragment. It is used to indent Fragments in
* a ConsoleReporter and to create a tree or Descriptions in the JUnit runner
*
* It does so by considering that some fragments have an effect on the indentation of the next fragment
*
* - a Text fragment is an Indent(1) so it indents the next fragment once
* - a Tab(n) fragment is an Indent(n) so it indents the next fragment n times
* - a Backtab(n) fragment is an Unindent(n) so it un-indents the next fragment n times
* - an Example fragment is a Terminal(), it doesn't do anything. This means that 2 consecutive examples will stay at the same level
* - an End fragment is a Reset, it set the level of the next fragment to 0 level
*
*/
case class Levels[T](private val levelsSeq: Vector[Level[T]] = Vector[Level[T]]()) {
/** @return true if there are no levels */
lazy val isEmpty = levelsSeq.isEmpty
/** @return alias for the last level */
lazy val level = levels.lastOption.map(_.level).getOrElse(0)
/** @return all the levels, computed with the LevelMonoid */
lazy val levels = {
import NestedBlocks._
def toNestedBlock(bl: Level[T]): SpecBlock[Level[T]] = bl match {
case b @ Level(s: SpecStart, l) => BlockStart(bl)
case b @ Level(s: ExecutedSpecStart, l) => BlockStart(bl)
case b @ Level(s: SpecEnd, l) => BlockEnd(bl)
case b @ Level(s: ExecutedSpecEnd, l) => BlockEnd(bl)
case b => BlockBit(bl)
}
sumContext(levelsSeq.map(toNestedBlock))(Levels.LevelMonoid[T])
}
/** @return the concatenation of 2 levels */
def add(other: Levels[T]) = Levels(levelsSeq ++ other.levelsSeq)
/**
* @return a Tree[T] based on the level of each block
*/
lazy val toTree: Tree[T] = toTreeLoc.toTree
/**
* map each node to another type given: the current type, the path from root (without the current node), the node number
*
* @return a Tree[S] based on the level of each block, mapping each node to value of type
* S and possibly skipping nodes
*/
def toTree[S](m: (T, Seq[S], Int) => Option[S]): Tree[S] = toTreeLoc(m).toTree
/**
* map each node to another type given: the current type, the node number
*
* @return a Tree[S] based on the level of each block, mapping each node to value of type
* S and possibly skipping nodes
*/
def toTree[S](m: (T, Int) => Option[S]): Tree[S] = {
def m1(t: T, s: Seq[S], i: Int) = m(t, i)
toTree[S](m1 _)
}
/**
* @return a TreeLoc[T] based on the level of each block
*/
lazy val toTreeLoc: TreeLoc[T] = toTreeLoc((t:T, parentsPath: Seq[T], i: Int) => Some(t))
/**
* WARNING this method assumes that the Levels are not empty!!
*
* @return a Tree[S] based on the level of each block, mapping each node to value of type
* S and possibly skipping nodes, passing the numeric label of the current node.
* @see JUnitDescriptions
*/
def toTreeLoc[S](m: (T, Seq[S], Int) => Option[S]): TreeLoc[S] = {
val initial = m(levels.head.t, Seq(), 0).get
levels.drop(1).foldLeft(leaf((initial, 0)).loc) { (res, cur) =>
val treeLoc = res
val Level(block, level) = cur
val parent = if (level == 0) treeLoc.root else (treeLoc.parentLocs :+ treeLoc).takeWhile(_.getLabel._2 < level).lastOption.getOrElse(treeLoc)
m(block, parent.path.reverse.toSeq.map(_._1), treeLoc.size) match {
case Some(s) => parent.insertDownLast(leaf((s, level)))
case None => treeLoc
}
}.map(_._1)
}
override def equals(a: Any) = {
a match {
case l: Levels[_] => levelsSeq.map(_.t).equals(l.levelsSeq.map(_.t))
case _ => false
}
}
}
private[specs2]
case object Levels {
/** @return a new Levels object for one Block */
def apply[T](b: Level[T]) = new Levels(Vector(b))
/** Semigroup for Level[T] */
implicit def LevelMonoid[T]: Monoid[Level[T]] = new Monoid[Level[T]] {
def append(l1: Level[T], l22: =>Level[T]) = {
val l2 = l22
(l1, l2) match {
case (LevelZero(), _) => l2
case (_, LevelZero()) => l1
case (Fixed(_, _, end), _) => l2.setLevel(end)
case (Indent(_, n), _) => l2.setLevel(l1.lv + n)
case (Unindent(_, n), _) => l2.setLevel(l1.lv - n)
case (Reset(_), _) => l2.reset
case (_, _) => l2.setLevel(l1.lv)
}
}
val zero: Level[T] = LevelZero[T]()
}
/** monoid for Levels, doing a simple aggregation */
implicit def LevelsConcatMonoid[T] = new Monoid[Levels[T]] {
def append(b1: Levels[T], b2: =>Levels[T]) = b1 add b2
val zero = new Levels[T]()
}
/** fold a list of T to a Levels object */
def foldAll[T](fs: Seq[T])(implicit reducer: Reducer[T, Levels[T]]) = fs.foldMap(reducer.unit)
implicit val LevelsReducer: Reducer[ExecutingFragment, Levels[Fragment]] =
Reducer.unitReducer { f: ExecutingFragment => Levels(fragmentToLevel(f.original)) }
implicit val LevelsReducer2: Reducer[ExecutingFragment, Level[Fragment]] =
Reducer.unitReducer { f: ExecutingFragment => fragmentToLevel(f.original) }
implicit val ExecutedLevelsReducer: Reducer[ExecutedFragment, Levels[ExecutedFragment]] =
Reducer.unitReducer { f: ExecutedFragment => Levels(executedFragmentToLevel(f)) }
implicit def executedFragmentToLevel: ExecutedFragment => Level[ExecutedFragment] = (f: ExecutedFragment) => f match {
case t @ ExecutedResult(_,_,_,_,_) => Terminal(t)
case t @ ExecutedText(Text(text, _), _) => if (text.flow) Fixed(t, startIndentation(text.raw), endIndentation(text.raw)) else Indent(t)
case t @ ExecutedTab(n, _) => Indent(t, n)
case t @ ExecutedBacktab(n, _) => Unindent(t, n)
case t @ ExecutedSpecStart(_,_,_) => Neutral(t)
case t @ ExecutedSpecEnd(_,_,_) => Neutral(t)
case t @ ExecutedEnd( _) => Reset(t)
case t => Neutral(t)
}
implicit val LevelReducer: Reducer[ExecutedFragment, Level[ExecutedFragment]] =
Reducer.unitReducer { f: ExecutedFragment => executedFragmentToLevel(f) }
implicit def fragmentToLevel: Fragment => Level[Fragment] = (f: Fragment) => f match {
case t: Example => Terminal(t)
case t @ Tab(n) => Indent(t, n)
case t @ Backtab(n) => Unindent(t, n)
case t: Text => if (t.text.flow) Fixed(t, startIndentation(t.text.raw), endIndentation(t.text.raw)) else Indent(t)
case t: SpecStart => Neutral(t)
case t: SpecEnd => Neutral(t)
case t @ End() => Reset(t)
case t => Neutral(t)
}
private[specs2] def startIndentation(text: String) =
text.split("\n").filter(_.nonEmpty).headOption.getOrElse("").takeWhile(_ == ' ').size
private[specs2] def endIndentation(text: String) =
text.split("\n").lastOption.getOrElse("").takeWhile(_ == ' ').size
implicit val FragmentLevelsReducer: Reducer[Fragment, Levels[Fragment]] =
Reducer.unitReducer { f: Fragment => Levels(fragmentToLevel(f)) }
implicit val FragmentLevelsReducer2: Reducer[Fragment, Level[Fragment]] =
Reducer.unitReducer { f: Fragment => fragmentToLevel(f) }
}
private[specs2]
abstract class Level[+T](val fragment: Option[T]) {
lazy val t: T = fragment.get
val lv: Int = 0
type L <: Level[T]
def level = math.max(lv, 0)
def setLevel(lv: Int): L
def reset: L = setLevel(0)
}
private[specs2]
case class Terminal[T](value: T) extends Level(Some(value)) {
type L = Terminal[T]
def setLevel(l: Int) = new Terminal(value) { override val lv = l }
}
private[specs2]
case class Indent[T](value: T, n: Int = 1) extends Level(Some(value)) {
type L = Indent[T]
def setLevel(l: Int) = new Indent(value, n) { override val lv = l }
}
private[specs2]
case class Fixed[T](value: T, start: Int = 0, end: Int = 0) extends Level(Some(value)) {
type L = Fixed[T]
override def level: Int = start
def setLevel(l: Int) = new Fixed(value, start, end) { override val lv = l }
}
private[specs2]
case class Unindent[T](value: T, n: Int = 1) extends Level(Some(value)) {
type L = Unindent[T]
def setLevel(l: Int) = new Unindent(value, n) { override val lv = l }
}
private[specs2]
case class Reset[T](value: T) extends Level(Some(value)) {
type L = Reset[T]
def setLevel(l: Int) = new Reset(value) { override val lv = l }
}
private[specs2]
case class Neutral[T](value: T) extends Level(Some(value)) {
type L = Neutral[T]
def setLevel(l: Int) = new Neutral(value) { override val lv = l }
}
private[specs2]
case class LevelZero[T]() extends Level[T](None) {
type L = LevelZero[T]
def setLevel(l: Int) = new LevelZero[T]() { override val lv = l }
}
private[specs2]
object Level {
def unapply[T](l: Level[T]): Option[(T, Int)] = Some((l.t, l.level))
}