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

org.specs2.runner.SpecificationsFinder.scala Maven / Gradle / Ivy

The newest version!
package org.specs2
package runner

import java.util.regex._
import io._
import reflect.Classes
import specification.SpecificationStructure
import main.Arguments

/**
 * This trait loads specifications found on a given source directory based
 * on a regular expression representing the Specification name, usually .*Spec
 */
trait SpecificationsFinder extends FileSystem with Classes with ConsoleOutput {
  private lazy val CLASSNAME_REGEX = "([\\p{L}_$][\\p{L}\\p{N}_$]*\\.)*[\\p{L}_$][\\p{L}\\p{N}_$]*".r
  /**
   * @param path a path to a directory containing scala files (it can be a glob: i.e. "dir/**/*spec.scala")
   * @param pattern a regular expression which is supposed to match an object name extending a Specification
   * @param filter a function to filter out unwanted specifications
   * @return specifications created from specification names
   */
  def specifications(path: String = "**/*.scala",
                     pattern: String = ".*Spec",
                     filter: String => Boolean = { (name: String) => true },
                     basePath: String = FromSource.srcDir,
                     verbose: Boolean = false)
                    (implicit args: Arguments = Arguments()): Seq[SpecificationStructure] =
    specificationNames(path, pattern, basePath, verbose).view.filter(filter).flatMap(n => createSpecification(n, verbose))
  /**
   * @param path a path to a directory containing scala files (it can be a glob: i.e. "dir/**/*spec.scala")
   * @param pattern a regular expression which is supposed to match an object name extending a Specification
   * @return specification names by scanning files and trying to find specifications declarations
   */
  def specificationNames(path: String = "**/*.scala",
                         pattern: String = ".*Spec",
                         basePath: String = FromSource.srcDir,
                         verbose: Boolean = false) : Seq[String] = {
    lazy val specClassPattern = {
      val p = specPattern("class", pattern)
      if (verbose) println("\nthe pattern used to match specification classes is: "+p+"\n")
      Pattern.compile(p)
    }
    lazy val specObjectPattern = {
      val p = specPattern("object", pattern)
      if (verbose) println("\nthe pattern used to match specification objects is: "+p+"\n")
      Pattern.compile(p)
    }
    filePaths(basePath, path, verbose) filter (_.endsWith(".scala")) flatMap { p =>
      val fileContent = readFile(p)
      val packName = packageName(fileContent)
      val (objectPattern, classPattern) = (specObjectPattern, specClassPattern)
      if (verbose) println("\nSearching for specifications in file: "+p)
      classNames(packName, fileContent, objectPattern, "$", verbose) ++ classNames(packName, fileContent, classPattern, "", verbose)
    }
   }

  /**
   * adds possible specification class names found in the file filePath
* The specification pattern is: "\\s*object\\s*(" + pattern + ")\\s*extends\\s*.*Spec.*\\s*\\{" * This may be later extended to support other arbitrary patterns * * @param packageName the base package for the class names * @param content content of the file * @param pattern a regular expression which is supposed to match an object name extending a Specification */ def classNames(packageName: String, content: String, pattern: Pattern, suffix: String, verbose: Boolean = false): Seq[String] = { def result(m: Matcher): Stream[String] = if (m.find) { val fullName = List(packageName, m.group(1).trim).mkString(".") + suffix Stream.cons(fullName, result(m)) } else Stream.empty val found = result(pattern.matcher(content)).toList if (verbose && found.nonEmpty) println("found the following specifications: "+found.mkString(",")) found.filter(c => CLASSNAME_REGEX.pattern.matcher(c).matches) } /** * pattern to use to get specification names from file contents */ def specPattern(specType: String, pattern: String) = "\\s*"+specType+"\\s*(" + pattern + ")\\s*extends\\s*.*" /** @return the package declaration at the beginning of a file */ def packageName(content: String): String = { def result(m: Matcher): Stream[String] = if (m.find) Stream.cons(m.group(1).replace(";", "").trim, result(m)) else Stream.empty val pattern = "\\s*package\\s*(.+)\\s*" result(Pattern.compile(pattern).matcher(content)).mkString(".") } /** * @return a SpecificationStructure object from a className if that class is a SpecificationStructure class.
* Tries to load the class name and cast it to a specification * None in case of an exception. */ def createSpecification(className: String, verbose: Boolean = false)(implicit args: Arguments): Option[SpecificationStructure] = { SpecificationStructure.createSpecificationEither(className) match { case Right(s) => Some(s) case Left(e) => { if (verbose) { println(e.getMessage); e.printStackTrace } None } } } /** * @return a SpecificationStructure object from a className if that class is a SpecificationStructure class.
* Tries to load the class name and cast it to a specification * None in case of an exception. */ def createSpecification(className: String, printMessage: Boolean, printStackTrace: Boolean): Option[SpecificationStructure] = createObject[SpecificationStructure](className, printMessage, printStackTrace) } object SpecificationsFinder extends SpecificationsFinder




© 2015 - 2025 Weber Informatics LLC | Privacy Policy