CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-scalatest--scalatest-2-11

ScalaTest is a comprehensive testing framework for Scala and Java that provides multiple testing styles and sophisticated matcher libraries.

Pending
Overview
Eval results
Files

scalactic-utilities.mddocs/

Scalactic Utilities

Scalactic provides functional programming utilities and better error handling mechanisms for Scala applications. The library focuses on functional idioms, type-safe error handling with the Or type, and pluggable equality systems.

Capabilities

Or Type System

Railway-oriented programming with Good/Bad disjunction type for error handling.

import org.scalactic._

// Core Or type
sealed abstract class Or[+G, +B] {
  // Type checking methods
  def isGood: Boolean
  def isBad: Boolean
  
  // Value extraction (unsafe)
  def get: G  // Throws if Bad
  
  // Safe value extraction
  def getOrElse[H >: G](alternative: => H): H
  
  // Transformation methods
  def map[H](f: G => H): H Or B
  def flatMap[H, C >: B](f: G => H Or C): H Or C
  def filter[C >: B](p: G => Boolean): G Or (B Or C)
  def foreach(f: G => Unit): Unit
  def fold[V](fa: B => V, fb: G => V): V
  
  // Collection-like operations
  def toOption: Option[G]
  def toSeq: Seq[G]
  def iterator: Iterator[G]
  
  // Combination methods
  def orElse[H >: G, C >: B](alternative: => H Or C): H Or C
  def recover[H >: G](pf: PartialFunction[B, H]): H Or B
  def recoverWith[H >: G, C >: B](pf: PartialFunction[B, H Or C]): H Or C
  
  // Validation methods
  def badMap[C](f: B => C): G Or C
  def swap: B Or G
  def exists(p: G => Boolean): Boolean
  def forall(p: G => Boolean): Boolean
}

// Concrete implementations
case class Good[+G](value: G) extends Or[G, Nothing]
case class Bad[+B](value: B) extends Or[Nothing, B]

// Companion object methods
object Or {
  def apply[G, B](value: G): G Or B = Good(value)
  def good[G, B](value: G): G Or B = Good(value)
  def bad[G, B](value: B): G Or B = Bad(value)
}

Or Type Examples:

import org.scalactic._

// Basic usage
def divide(x: Int, y: Int): Int Or String = {
  if (y == 0) Bad("Cannot divide by zero")
  else Good(x / y)
}

val result1 = divide(10, 2)  // Good(5)
val result2 = divide(10, 0)  // Bad("Cannot divide by zero")

// Pattern matching
result1 match {
  case Good(value) => println(s"Result: $value")
  case Bad(error) => println(s"Error: $error")
}

// Functional operations
val doubled = result1.map(_ * 2)  // Good(10)
val recovered = result2.getOrElse(-1)  // -1

// Chaining operations
def parseAndDivide(xStr: String, yStr: String): Int Or String = {
  for {
    x <- parseIntSafely(xStr)
    y <- parseIntSafely(yStr)
    result <- divide(x, y)
  } yield result
}

def parseIntSafely(str: String): Int Or String = {
  try Good(str.toInt)
  catch { case _: NumberFormatException => Bad(s"Not a valid integer: $str") }
}

Attempt Function

Safe execution wrapper that catches exceptions and returns Or.

import org.scalactic._

/**
 * Returns the result of evaluating the given block f, wrapped in a Good, or
 * if an exception is thrown, the Throwable, wrapped in a Bad.
 */
def attempt[R](f: => R): R Or Throwable

Attempt Examples:

import org.scalactic._

// Safe division
val result1 = attempt { 10 / 2 }  // Good(5)
val result2 = attempt { 10 / 0 }  // Bad(ArithmeticException)

// Safe file operations
def readFileSafely(filename: String): String Or Throwable = {
  attempt {
    scala.io.Source.fromFile(filename).mkString
  }
}

// Chaining with other Or operations
val processedResult = for {
  content <- readFileSafely("data.txt")
  lines = content.split("\n")
  firstLine <- if (lines.nonEmpty) Good(lines.head) else Bad("File is empty")
} yield firstLine.toUpperCase

Equality System

Pluggable equality for custom comparison logic.

import org.scalactic._

// Core equality trait
trait Equality[T] {
  def areEqual(a: T, b: Any): Boolean
}

// Normalization trait
trait Uniformity[T] extends Equality[T] {
  def normalized(a: T): T
  def normalizedCanHandle(b: Any): Boolean
  def normalizedOrSame(b: Any): Any
}

// Explicitly object for controlling implicit conversions
object Explicitly {
  val decided: Decided.type = Decided
  val after: After.type = After
}

// Custom equality examples
implicit val stringEquality = new Equality[String] {
  def areEqual(a: String, b: Any): Boolean = 
    b match {
      case s: String => a.toLowerCase == s.toLowerCase
      case _ => false
    }
}

Equality Examples:

import org.scalactic._
import org.scalactic.StringNormalizations._

// Case-insensitive string equality
implicit val caseInsensitiveEquality = new Equality[String] {
  def areEqual(a: String, b: Any): Boolean = 
    b match {
      case s: String => a.toLowerCase == s.toLowerCase  
      case _ => false
    }
}

// Using with ScalaTest matchers
"Hello" should equal("HELLO")(decided by caseInsensitiveEquality)

// Normalization-based equality
implicit val trimmedStringEquality = StringNormalizations.trimmed

"  hello  " should equal("hello")(after being trimmed)

// Custom numeric tolerance
implicit val doubleEquality = TolerantNumerics.tolerantDoubleEquality(0.01)
3.14159 should equal(3.14)(decided by doubleEquality)

Validated Types (AnyVals)

Type-safe wrappers for constrained values.

import org.scalactic.anyvals._

// Positive integers
final class PosInt private (val value: Int) extends AnyVal
object PosInt {
  def from(value: Int): PosInt Or One[ErrorMessage]
  def ensuringValid(value: Int): PosInt
}

// Non-zero integers  
final class NonZeroInt private (val value: Int) extends AnyVal
object NonZeroInt {
  def from(value: Int): NonZeroInt Or One[ErrorMessage]
  def ensuringValid(value: Int): NonZeroInt
}

// Positive doubles
final class PosDouble private (val value: Double) extends AnyVal
object PosDouble {
  def from(value: Double): PosDouble Or One[ErrorMessage]
  def ensuringValid(value: Double): PosDouble
}

// Non-empty strings
final class NonEmptyString private (val value: String) extends AnyVal
object NonEmptyString {
  def from(value: String): NonEmptyString Or One[ErrorMessage]
  def ensuringValid(value: String): NonEmptyString
}

// Non-empty collections
final class NonEmptyList[+T] private (val value: List[T]) extends AnyVal
object NonEmptyList {
  def from[T](value: List[T]): NonEmptyList[T] Or One[ErrorMessage]
  def apply[T](head: T, tail: T*): NonEmptyList[T]
}

Validated Types Examples:

import org.scalactic.anyvals._

// Safe construction with validation
val posInt1 = PosInt.from(5)           // Good(PosInt(5))
val posInt2 = PosInt.from(-5)          // Bad(One("-5 was not greater than 0"))

// Unsafe construction (throws on invalid)
val posInt3 = PosInt.ensuringValid(10) // PosInt(10)

// Using in function parameters
def calculateArea(width: PosDouble, height: PosDouble): Double = {
  width.value * height.value
}

val width = PosDouble.from(5.0).getOrElse(PosDouble.ensuringValid(1.0))
val height = PosDouble.from(3.0).getOrElse(PosDouble.ensuringValid(1.0))
val area = calculateArea(width, height)

// Non-empty collections
val nonEmptyList = NonEmptyList(1, 2, 3, 4)  // NonEmptyList(List(1, 2, 3, 4))
val fromList = NonEmptyList.from(List(1, 2)) // Good(NonEmptyList(List(1, 2)))
val fromEmpty = NonEmptyList.from(List.empty) // Bad(One("List was empty"))

// Working with validated strings
def processName(name: NonEmptyString): String = {
  s"Hello, ${name.value}!"
}

NonEmptyString.from("Alice") match {
  case Good(name) => processName(name)
  case Bad(error) => s"Invalid name: ${error.head}"
}

Requirements and Assertions

Design by contract utilities for preconditions and postconditions.

import org.scalactic._

object Requirements {
  // Precondition checking
  def require(condition: Boolean): Unit
  def require(condition: Boolean, message: => Any): Unit
  
  // Null checking
  def requireNonNull(reference: AnyRef): Unit
  def requireNonNull(reference: AnyRef, message: => Any): Unit
  
  // State checking
  def requireState(condition: Boolean): Unit
  def requireState(condition: Boolean, message: => Any): Unit
}

// Chain type (deprecated, use NonEmptyList)
@deprecated("Use NonEmptyList instead")
type Chain[+T] = NonEmptyList[T]

Requirements Examples:

import org.scalactic.Requirements._

class BankAccount(initialBalance: Double) {
  require(initialBalance >= 0, "Initial balance cannot be negative")
  
  private var balance = initialBalance
  
  def withdraw(amount: Double): Unit = {
    require(amount > 0, "Withdrawal amount must be positive")
    requireState(balance >= amount, "Insufficient funds")
    balance -= amount
  }
  
  def deposit(amount: Double): Unit = {
    require(amount > 0, "Deposit amount must be positive")
    balance += amount
  }
  
  def getBalance: Double = balance
}

// Usage
val account = new BankAccount(100.0)
account.deposit(50.0)    // OK
account.withdraw(75.0)   // OK
// account.withdraw(100.0)  // Would throw IllegalStateException

Snapshots and Pretty Printing

Enhanced error messages and value formatting.

import org.scalactic._

// Pretty printing customization
trait Prettifier {
  def apply(o: Any): String
}

object Prettifier {
  val default: Prettifier
  val truncateAt: Int => Prettifier
  val lineSeparator: String => Prettifier
}

// Position tracking for better error messages
package object source {
  case class Position(fileName: String, filePath: String, lineNumber: Int)
  
  implicit def here: Position = macro PositionMacro.genPosition
}

Collection Utilities

Additional collection operations and utilities.

// Every type for expressing "all elements match"
final class Every[+T] private (underlying: Vector[T]) {
  def map[U](f: T => U): Every[U]
  def flatMap[U](f: T => Every[U]): Every[U]
  def filter(p: T => Boolean): Seq[T]
  def exists(p: T => Boolean): Boolean
  def forall(p: T => Boolean): Boolean
  def toVector: Vector[T]
  def toList: List[T]
  def toSeq: Seq[T]
}

object Every {
  def apply[T](firstElement: T, otherElements: T*): Every[T]
  def from[T](seq: Seq[T]): Every[T] Or One[ErrorMessage]
}

// One type for single-element collections
final class One[+T](element: T) {
  def map[U](f: T => U): One[U]
  def flatMap[U](f: T => One[U]): One[U]
  def head: T
  def toSeq: Seq[T]
  def toList: List[T]
  def toVector: Vector[T]
}

Package Object Utilities

package object scalactic {
  // Type aliases
  type ErrorMessage = String
  
  // Utility functions
  def attempt[R](f: => R): R Or Throwable
  
  // Version information
  val ScalacticVersion: String
  
  // Deprecated aliases (use new names instead)
  @deprecated("Use NonEmptyList instead")
  type Chain[+T] = NonEmptyList[T]
  
  @deprecated("Use NonEmptyList instead") 
  val Chain = NonEmptyList
  
  @deprecated("Use anyvals.End instead")
  val End = anyvals.End
}

Integration with ScalaTest

Scalactic integrates seamlessly with ScalaTest for enhanced testing capabilities:

import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import org.scalactic._

class ScalacticIntegrationSpec extends AnyFlatSpec with Matchers {
  "Or type" should "work with ScalaTest matchers" in {
    val result: Int Or String = Good(42)
    
    result shouldBe a[Good[_]]
    result.isGood should be(true)
    result.get should be(42)
  }
  
  "Custom equality" should "be usable in tests" in {
    implicit val caseInsensitive = new Equality[String] {
      def areEqual(a: String, b: Any): Boolean = 
        b match {
          case s: String => a.toLowerCase == s.toLowerCase
          case _ => false
        }
    }
    
    "Hello" should equal("HELLO")(decided by caseInsensitive)
  }
  
  "Validated types" should "ensure constraints" in {
    val posInt = PosInt.from(5)
    posInt shouldBe a[Good[_]]
    posInt.get.value should be(5)
    
    val invalidPosInt = PosInt.from(-1)
    invalidPosInt shouldBe a[Bad[_]]
  }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-scalatest--scalatest-2-11

docs

assertions-matchers.md

async-testing.md

index.md

scalactic-utilities.md

test-execution.md

test-styles.md

tile.json