diff --git a/.github/workflows/test_and_release.yml b/.github/workflows/test_and_release.yml new file mode 100644 index 0000000..6725587 --- /dev/null +++ b/.github/workflows/test_and_release.yml @@ -0,0 +1,81 @@ +name: Test code, update coverage, and release master branch + +on: [ push, pull_request ] + +jobs: + test: + strategy: + matrix: + os: [ windows-latest, ubuntu-latest ] + java: [ '11', '17', '21' ] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4.2.2 + - name: Setup JDK + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: ${{ matrix.java }} + - name: Setup sbt launcher + uses: sbt/setup-sbt@v1.1.7 + - name: Run tests + shell: bash + run: sbt +test + coverage: + runs-on: ubuntu-latest + needs: test + steps: + - uses: actions/checkout@v4.2.2 + - name: Setup JDK + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 21 + - name: Setup sbt launcher + uses: sbt/setup-sbt@v1.1.7 + - name: Analyze coverage + run: sbt clean coverage +test + - name: Update coverage report + env: + COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COVERALLS_FLAG_NAME: Scala ${{ matrix.scala }} + run: sbt coverageReport coveralls + release: + runs-on: ubuntu-latest + needs: [ test, coverage ] + steps: + - uses: actions/checkout@v4.2.2 + - name: Check if we are head of master + id: check_head_of_master + run: | + git fetch origin master && + MASTER=`git rev-parse origin/master` && + echo "::set-output name=head_of_master::$MASTER" && + CURRENT=`git rev-list -n 1 ${{ github.ref }} || echo "NOT_MASTER"` && + echo "::set-output name=current_job_ref::$CURRENT" + - name: Set up JDK + if: steps.check_head_of_master.outputs.head_of_master == steps.check_head_of_master.outputs.current_job_ref + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 21 + - name: Set up SBT + if: steps.check_head_of_master.outputs.head_of_master == steps.check_head_of_master.outputs.current_job_ref + uses: sbt/setup-sbt@v1.1.7 + - name: Build and release + if: steps.check_head_of_master.outputs.head_of_master == steps.check_head_of_master.outputs.current_job_ref + env: + SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} + SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} + SONA_USER: ${{ secrets.SONATYPE_USERNAME }} + SONA_PASS: ${{ secrets.SONATYPE_PASSWORD }} + GPG_PRIVATE: ${{ secrets.GPG_PRIVATE }} + PGP_PASS: ${{ secrets.PGP_PASS }} + CI: github + run: | + git fetch --prune --unshallow --tags && + export GPG_TTY=$(tty) && + echo $GPG_PRIVATE | base64 -d | gpg --passphrase=$PGP_PASS --yes --batch --pinentry-mode loopback --import && + export PATH=`pwd`/.github/bin:$PATH && + sbt + test ciReleaseTagNextVersion ciReleaseSonatype + diff --git a/.scalafmt.conf b/.scalafmt.conf new file mode 100644 index 0000000..ca9f6ca --- /dev/null +++ b/.scalafmt.conf @@ -0,0 +1,10 @@ +version = 3.9.4 +rewrite.rules = [ AvoidInfix, SortImports ] +runner.dialect = scala36 +project { + git = true + excludeFilters = [ + plugin/src/sbt-test + ] + layout = StandardConvention +} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 6891398..0000000 --- a/.travis.yml +++ /dev/null @@ -1,30 +0,0 @@ -sudo: false -language: scala -stages: - - test - - name: deploy - if: branch = master AND NOT type IN (pull_request) - -script: sbt +test - -jobs: - include: - - dist: trusty - stage: test - jdk: oraclejdk8 - - stage: test - jdk: openjdk11 - script: sbt clean test && - sbt coverage ++2.12.10 test && - sbt ++2.12.10 coverageReport coveralls - - stage: deploy - jdk: openjdk11 - script: | - openssl aes-256-cbc -K $encrypted_edd93504cc75_key -iv $encrypted_edd93504cc75_iv -in travis/secrets.tar.enc -out travis/local.secrets.tar -d && - tar xv -C travis -f travis/local.secrets.tar && - sbt +releaseEarly -env: - global: - - secure: oaQO0OktBq1UUw490+zw/bioSFmfkHz9X7sLpoOCT9NzAPwHOXDNIaoYubu+HXbgvSfsId+x4QR2wT1cH+njBMwvImQWrkfWODTAxfSVEuqThWlVKTmfYCoNcbMpFOIQYpSWqx7pb8VeNMr1p2Ql6ov3lNvUpRNvIwxbfUBCYy3mL/H4/1XFDy7emSmgr/I56Pmg6woMi7T7zoEFMozKPQG2rkB3/yU53CtRWMTDU4p3R33bFP5+Q314jkLN/x8E6p83DXSlHw5CNCybrndvBN2Ugylpn5XbINyW78yEc1uDpMDjgQ6/nFldFLBsZ9jVJNOLFHwxEcPCHKS22SVZ50mpek5zvUDHGKGodl2Ct1J2dO/kV3Mk15y/ndiapUJvZ/JLUwbgNmF1zzTsrvWdGiHnPOz4MWfkUAe5L8pAVNs0wul0AihbkcthD2hQu3EnDxjx1Mf0yjov58orv7q0Euf7Wnmzmu9orx+KBbCX7UFs6SsFZiM8jbyEy50K+Evmub1Qd+UYc/xspboM6vidKd61+O2YTnQ26MsFV0cn6GvkphqsbjfSep/cvm9gOtYiwo959v7MX8ApMXU28hK01rf0BlnBBVuXd8cNuTW7B6SAQM1HRxjkfze6VukGYQFe8RLuuhqfbAXCpui1lcKaQf2G9jTrse0+ROszqqLEaTU= - - secure: BNveA1KQHK2DWg4Q4Oogvo3BDZP17zHjMiEf1JzIt06dB3QZ4ZYONTOPgXvL3XrFGJZe40pnAmrQezlrpRK2X8JPNbYpYh7aHB6AGQmJzHU1BNVI/0GuN+y0jUJaM8oH83z2S4sm8BZA015YIWmV8P0OELcTNxglgOwj9yo0SB5Xrd7qeAfmho9Lg1pN42LhuZK8LzxsTtrInR9k2dYKIsIwEkrNSqycqOVs1mLGX++wvj3qGf4a2GibswhQ3k1rG5jfeT9HjHDzFdWlOvn4jH8TasA3yBoNCgUEA8lIR9fSKGkbS72o4X5OsOLP6qykobcLAIK7SAFOXRY1xhJESFgLBIQQa09XmI0T3YLglXIdz78m/4stQ4firF249Ph3Uj2656uiiwGgCNku6kRDNj9HN5y/RtsZaoNC304nrXYpIhMPNFuekfcmB7fWhczsU0aXzfRBvjrXWq+jpFoKh2En6WFDEeMaDTmbGdN4Qyb1zL1Yw2lXdg2Blxm24H+E5J4FHnCSJU81xmAzR4LgBEqQdGJW0n31mMgXG9NNJEPjo1hYn/OvXDIQOhg3IO0OENX3PS8UxtlhX1/fMyLVN/JmHdXUR1r0b/v/NtKrYlZgveJ5EB162NYGy8QKT2K2iDjk1nkBJ8GFNocaXWmAjsmAb5A2lBYMZYULMrLTTjM= - - secure: DKrbKFUrrnFC7JTgDWf0w8KIqT/3dHJphVKv4UkvvLJ7vuCWYQ+82QRzey/LFGCGq4nS545qWyZBZDXHQbBukJZuC+rqilcXRoE05QP42PuWhDJ00f68U5ciE5D5o9S7qGwo2zKFxt7g8pGuebQBb0BYrV9ilAbCF7wVGdWfkjq4h65nPcMJNaXoq7sDcIDXdnKbYBE5KFjglv5coRkyLm+LSyPbPClt+fnCJq6lYFXTqoecWOWMiCQdnCmanWB4Av/AYfuGOt6nIR8WTpHOT/KMkvKv/lNJ2p+mCRe22Th9eKQZvep/XPtwaueYO/c0zpc/dz7XEapXhzdoEGDhLRZfiuy1fXyHuMb4vhLYJBZ3d1t3hN5IkK/1RFWF6PCdoRYnxrMYbMT2uJTA3sVVA8YBQw99OkV9Y/N/SSAkSkJnCuaCeiLPb/OMZlxLY6hs93HbLDBDp935wRL8UZnsLA/bq6/1i7USF4HwI2aZQbhzbbqSXnVbtPvdTQEx4dORWenJraIBl+6LGKA93vimOxi8GkqAbAlgIeUvPH24t4yvHbX+AHCLpHTL7sS6Fl1gc3VLJrzPs21tliNOA3DYjXvNkYZRsdppGXR3nlCuUFlN9hd6pf0WJtYQUrjVPPJ7Nthx2J1y/o5HWAxHpNB9829djuG+nFvXPWJHfYZeNKI= diff --git a/README.md b/README.md index e598bb9..b14e1ae 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ You can search for released versions [here](http://search.maven.org/#search%7Cga To obtain the latest unreleased development version, clone the repository and run `sbt publishLocal`. -Currently, Scala 2.11, 2.12 and 2.13 are supported. +Currently, Scala 2.13, 3.3 and 3.6 are supported. ## Examples diff --git a/build.sbt b/build.sbt index 6b4edeb..1b00240 100644 --- a/build.sbt +++ b/build.sbt @@ -4,24 +4,28 @@ import sbt.Resolver lazy val commonSettings = Seq( organization := "org.combinators", - scalaVersion := "2.13.1", - crossScalaVersions := Seq("2.11.12", "2.12.10", scalaVersion.value), + scalaVersion := "3.6.4", + crossScalaVersions := Seq("2.13.16", "3.3.5", scalaVersion.value), - resolvers ++= Seq( - Resolver.sonatypeRepo("releases"), - Resolver.typesafeRepo("releases"), - Resolver.sonatypeRepo("snapshots"), - Resolver.typesafeRepo("snapshots") - ), + resolvers ++= Resolver.sonatypeOssRepos("releases"), + resolvers += Resolver.typesafeRepo("releases"), - headerLicense := Some(HeaderLicense.ALv2("2017-2019", "Jan Bessai")), + headerLicense := Some(HeaderLicense.ALv2("2017-2025", "Jan Bessai")), scalacOptions ++= Seq( "-unchecked", "-deprecation", "-feature", "-language:implicitConversions" - ) + ), + scalacOptions ++= { + if (scalaVersion.value >= "2.13.14" && scalaVersion.value < "3.0") Seq( + // "-Xsource:3", + "-Xsource:3-cross" + ) + else Nil + }, + ThisBuild/scapegoatVersion := "3.1.8" ) ++ publishSettings lazy val root = (Project(id = "templating", base = file("."))) @@ -31,16 +35,15 @@ lazy val root = (Project(id = "templating", base = file("."))) .settings( moduleName := "templating", libraryDependencies ++= Seq( - "org.scalactic" %% "scalactic" % "3.0.8" % "test", - "org.scalatest" %% "scalatest" % "3.0.8" % "test", - "com.github.javaparser" % "javaparser-core" % "3.14.14", - "org.apache.commons" % "commons-text" % "1.8", - "commons-io" % "commons-io" % "2.6" % "test", - "org.scala-lang.modules" %% "scala-collection-compat" % "2.1.2" + "org.scalactic" %% "scalactic" % "3.2.19" % "test", + "org.scalatest" %% "scalatest" % "3.2.19" % "test", + "com.github.javaparser" % "javaparser-core" % "3.26.4", + "org.apache.commons" % "commons-text" % "1.13.1", + "commons-io" % "commons-io" % "2.19.0" % "test" ), - sourceDirectories in (Test, TwirlKeys.compileTemplates) += sourceDirectory.value / "test" / "java-templates", - resourceDirectories in Test += sourceDirectory.value / "resources", + Test / TwirlKeys.compileTemplates / sourceDirectories += sourceDirectory.value / "test" / "java-templates", + Test / resourceDirectories += sourceDirectory.value / "resources", TwirlKeys.templateImports := Seq(), TwirlKeys.templateFormats += ("java" -> "org.combinators.templating.twirl.JavaFormat"), TwirlKeys.templateImports += "scala.collection.immutable._", @@ -53,7 +56,7 @@ lazy val root = (Project(id = "templating", base = file("."))) TwirlKeys.templateImports += "com.github.javaparser.ast.stmt._", TwirlKeys.templateImports += "com.github.javaparser.ast.`type`._", - sourceDirectories in (Test, TwirlKeys.compileTemplates) += sourceDirectory.value / "test" / "python-templates", + Test / TwirlKeys.compileTemplates / sourceDirectories += sourceDirectory.value / "test" / "python-templates", TwirlKeys.templateFormats += ("py" -> "org.combinators.templating.twirl.PythonFormat"), TwirlKeys.templateImports += "org.combinators.templating.twirl.Python" ) @@ -64,13 +67,11 @@ lazy val publishSettings = Seq( licenses := Seq("Apache 2" -> url("http://www.apache.org/licenses/LICENSE-2.0.txt")), scmInfo := Some(ScmInfo(url("https://www.github.com/combinators/templating"), "scm:git:git@github.com:combinators/templating.git")), developers := List( - Developer("JanBessai", "Jan Bessai", "jan.bessai@tu-dortmund.de", url("http://janbessai.github.io")), + Developer("JanBessai", "Jan Bessai", "jan.bessai@tu-dortmund.de", url("http://noprotocol.net")), Developer("heineman", "George T. Heineman", "heineman@wpi.edu", url("http://www.cs.wpi.edu/~heineman")), Developer("BorisDuedder", "Boris Düdder", "boris.d@di.ku.dk", url("http://duedder.net")) ), - - pgpPublicRing := file("travis/local.pubring.asc"), - pgpSecretRing := file("travis/local.secring.asc"), + publishTo := sonatypePublishToBundle.value, ) lazy val noPublishSettings = Seq( diff --git a/project/build.properties b/project/build.properties index dca663d..53bb739 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version = 1.2.8 +sbt.version = 1.10.11 diff --git a/project/plugins.sbt b/project/plugins.sbt index fad8e57..ee7a024 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,7 +1,8 @@ logLevel := Level.Warn -addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.10") -addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.6.0") -addSbtPlugin("org.scoverage" % "sbt-coveralls" % "1.2.7") -addSbtPlugin("com.typesafe.sbt" % "sbt-twirl" % "1.4.2") -addSbtPlugin("ch.epfl.scala" % "sbt-release-early" % "2.1.1") -addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.2.0") +addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.3.1") +addSbtPlugin("org.scoverage" % "sbt-coveralls" % "1.3.15") +addSbtPlugin("org.playframework.twirl" % "sbt-twirl" % "2.0.8") +addSbtPlugin("io.shiftleft" % "sbt-ci-release-early" % "2.0.49") +addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.10.0") +addSbtPlugin("com.sksamuel.scapegoat" %% "sbt-scapegoat" % "1.2.12") +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.4") diff --git a/src/main/scala/org/combinators/templating/persistable/JavaPersistable.scala b/src/main/scala/org/combinators/templating/persistable/JavaPersistable.scala index 9b677f9..cb6b008 100644 --- a/src/main/scala/org/combinators/templating/persistable/JavaPersistable.scala +++ b/src/main/scala/org/combinators/templating/persistable/JavaPersistable.scala @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 Jan Bessai + * Copyright 2017-2025 Jan Bessai * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,35 +23,38 @@ import com.github.javaparser.ast.expr.{Name, NameExpr} import com.github.javaparser.ast.visitor.GenericVisitorAdapter import scala.collection.immutable._ -import scala.collection.compat._ import scala.jdk.CollectionConverters._ trait JavaPersistableInstances { - /** Persistable instance for a compilation unit. - * Derives path and file names from the package and the name of the first declared type. + + /** Persistable instance for a compilation unit. Derives path and file names + * from the package and the name of the first declared type. */ implicit def compilationUnitInstance: JavaPersistable.Aux[CompilationUnit] = new Persistable { type T = CompilationUnit - override def rawText(compilationUnit: CompilationUnit) = compilationUnit.toString.getBytes + override def rawText(compilationUnit: CompilationUnit) = + compilationUnit.toString.getBytes override def path(compilationUnit: CompilationUnit) = { val pkg: Seq[String] = compilationUnit.getPackageDeclaration.orElse(null) match { case null => Seq.empty case somePkg => - somePkg.accept(new GenericVisitorAdapter[Seq[String], Unit] { - override def visit(name: NameExpr, arg: Unit): Seq[String] = Seq(name.getNameAsString) - override def visit(name: Name, arg: Unit): Seq[String] = - Option(name.getQualifier.orElse(null)) - .map((q: Name) => q.accept(this, arg)) - .getOrElse(Seq.empty[String]) :+ name.getIdentifier - }, + somePkg.accept( + new GenericVisitorAdapter[Seq[String], Unit] { + override def visit(name: NameExpr, arg: Unit): Seq[String] = + Seq(name.getNameAsString) + override def visit(name: Name, arg: Unit): Seq[String] = + Option(name.getQualifier.orElse(null)) + .map((q: Name) => q.accept(this, arg)) + .getOrElse(Seq.empty[String]) :+ name.getIdentifier + }, () ) } val clsName = s"${compilationUnit.getTypes.asScala.head.getName}.java" val fullPath = "src" +: "main" +: "java" +: pkg :+ clsName - Paths.get(fullPath.head, fullPath.tail : _*) + Paths.get(fullPath.head, fullPath.tail*) } } } @@ -59,4 +62,4 @@ trait JavaPersistableInstances { object JavaPersistable extends JavaPersistableInstances { type Aux[TT] = Persistable { type T = TT } def apply[T](implicit persistable: Aux[T]): Aux[T] = persistable -} \ No newline at end of file +} diff --git a/src/main/scala/org/combinators/templating/persistable/Persistable.scala b/src/main/scala/org/combinators/templating/persistable/Persistable.scala index 88e80b8..cc99e8c 100644 --- a/src/main/scala/org/combinators/templating/persistable/Persistable.scala +++ b/src/main/scala/org/combinators/templating/persistable/Persistable.scala @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 Jan Bessai + * Copyright 2017-2025 Jan Bessai * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,24 +21,27 @@ import java.io.File /** Type class for persistable objects (inhabitants). */ trait Persistable { + /** The type of the object to persist */ type T + /** Serialized representation of the object */ def rawText(elem: T): Array[Byte] - /** Path where to store the object `elem` (relative to some later specified root) */ + + /** Path where to store the object `elem` (relative to some later specified + * root) + */ def path(elem: T): Path - /** - * Computes the full path where to place `elem` relative to `basePath`. + /** Computes the full path where to place `elem` relative to `basePath`. */ def fullPath(basePath: Path, elem: T): Path = { basePath.resolve(path(elem)) } - - /** - * Persists this object to an object dependent path under `basePath` and returns the persisted file. - * Overwrites any pre-existing files under `basePath` / `path`. + /** Persists this object to an object dependent path under `basePath` and + * returns the persisted file. Overwrites any pre-existing files under + * `basePath` / `path`. */ def persistOverwriting(basePath: Path, elem: T): File = { val fp = fullPath(basePath, elem) @@ -48,9 +51,9 @@ trait Persistable { fp.toFile } - /** - * Persists this object to an object dependent path under `basePath` and returns the persisted file. - * Throws an `FileAlreadyExistsException` if the file already exists. + /** Persists this object to an object dependent path under `basePath` and + * returns the persisted file. Throws an `FileAlreadyExistsException` if the + * file already exists. */ def persist(basePath: Path, elem: T): File = { val fp = fullPath(basePath, elem) @@ -64,4 +67,4 @@ object Persistable { type Aux[TT] = Persistable { type T = TT } def apply[T](implicit persistable: Aux[T]): Aux[T] = persistable -} \ No newline at end of file +} diff --git a/src/main/scala/org/combinators/templating/persistable/PythonWithPathPersistable.scala b/src/main/scala/org/combinators/templating/persistable/PythonWithPathPersistable.scala index ab09a4c..058989e 100644 --- a/src/main/scala/org/combinators/templating/persistable/PythonWithPathPersistable.scala +++ b/src/main/scala/org/combinators/templating/persistable/PythonWithPathPersistable.scala @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 Jan Bessai + * Copyright 2017-2025 Jan Bessai * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,8 +24,10 @@ import org.combinators.templating.twirl.Python case class PythonWithPath(code: Python, persistTo: Path) trait PythonWithPathPersistableInstances { + /** Persistable instance for [PythonWithPath]. */ - implicit def pythonWithPathPersistable: PythonWithPathPersistable.Aux[PythonWithPath] = new Persistable { + implicit def pythonWithPathPersistable + : PythonWithPathPersistable.Aux[PythonWithPath] = new Persistable { type T = PythonWithPath def rawText(elem: PythonWithPath): Array[Byte] = elem.code.getCode.getBytes def path(elem: PythonWithPath): Path = elem.persistTo diff --git a/src/main/scala/org/combinators/templating/persistable/ResourcePersistable.scala b/src/main/scala/org/combinators/templating/persistable/ResourcePersistable.scala index be0a627..7ad640b 100644 --- a/src/main/scala/org/combinators/templating/persistable/ResourcePersistable.scala +++ b/src/main/scala/org/combinators/templating/persistable/ResourcePersistable.scala @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 Jan Bessai + * Copyright 2017-2025 Jan Bessai * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,18 +20,27 @@ import java.nio.file.{Files, Path, Paths} /** A persistable resource on the classpath. * - * @param name the name by which to locate the resource within the classpath. - * @param persistTo the name of the file where to store the resource. - * @param classToLoadResource the class which will be used to load the resource (@see + * @param name + * the name by which to locate the resource within the classpath. + * @param persistTo + * the name of the file where to store the resource. + * @param classToLoadResource + * the class which will be used to load the resource (@see */ -case class BundledResource(name: String, persistTo: Path, classToLoadResource: Class[_] = getClass) +case class BundledResource( + name: String, + persistTo: Path, + classToLoadResource: Class[?] = classOf[BundledResource] +) trait ResourcePersistableInstances { def bundledResourceInstance: ResourcePersistable.Aux = new Persistable { override type T = BundledResource override def path(elem: BundledResource): Path = elem.persistTo override def rawText(elem: BundledResource): Array[Byte] = - Files.readAllBytes(Paths.get(elem.classToLoadResource.getResource(elem.name).toURI)) + Files.readAllBytes( + Paths.get(elem.classToLoadResource.getResource(elem.name).toURI) + ) } } diff --git a/src/main/scala/org/combinators/templating/twirl/Java.scala b/src/main/scala/org/combinators/templating/twirl/Java.scala index 955b3ea..7dfba27 100644 --- a/src/main/scala/org/combinators/templating/twirl/Java.scala +++ b/src/main/scala/org/combinators/templating/twirl/Java.scala @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 Jan Bessai + * Copyright 2017-2025 Jan Bessai * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,19 +20,24 @@ import java.io.StringReader import com.github.javaparser._ import com.github.javaparser.ast.`type`.Type -import com.github.javaparser.ast.body.{BodyDeclaration, ConstructorDeclaration, FieldDeclaration, MethodDeclaration} +import com.github.javaparser.ast.body.{ + BodyDeclaration, + ConstructorDeclaration, + FieldDeclaration, + MethodDeclaration +} import com.github.javaparser.ast.expr.{Expression, Name, NameExpr, SimpleName} import com.github.javaparser.ast.stmt.Statement import com.github.javaparser.ast.{CompilationUnit, ImportDeclaration, Node} import org.apache.commons.text.StringEscapeUtils import play.twirl.api.{BufferedContent, Format, Formats} -import scala.collection.compat._ import scala.collection.immutable._ import scala.jdk.CollectionConverters._ /** A Java fragment. */ -class Java private(elements: Seq[Java], text: String) extends BufferedContent[Java](elements, text) { +class Java private (elements: Seq[Java], text: String) + extends BufferedContent[Java](elements, text) { def this(text: String) = this(Nil, Formats.safe(text)) def this(elements: Seq[Java]) = this(elements, "") @@ -45,7 +50,8 @@ class Java private(elements: Seq[Java], text: String) extends BufferedContent[Ja def compilationUnit(): CompilationUnit = StaticJavaParser.parse(fullText) /** Parses an import declaration. */ - def importDeclaration(): ImportDeclaration = StaticJavaParser.parseImport(fullText) + def importDeclaration(): ImportDeclaration = + StaticJavaParser.parseImport(fullText) /** Parses this element as a single statement. */ def statement(): Statement = StaticJavaParser.parseStatement(fullText) @@ -55,7 +61,8 @@ class Java private(elements: Seq[Java], text: String) extends BufferedContent[Ja StaticJavaParser.parseBlock(s"{ $fullText }").getStatements.asScala.to(Seq) /** Parses this element as an expression. */ - def expression[T <: Expression](): T = StaticJavaParser.parseExpression[T](fullText) + def expression[T <: Expression](): T = + StaticJavaParser.parseExpression[T](fullText) /** Parses this element as a (potentially qualified) name. */ def name(): Name = StaticJavaParser.parseName(fullText) @@ -66,12 +73,22 @@ class Java private(elements: Seq[Java], text: String) extends BufferedContent[Ja /** Parses this element as a (unqualified) name expression. */ def nameExpression(): NameExpr = expression() - /** Parses this element as a class body declaration (e.g. a method or a field). */ - def classBodyDeclaration(): BodyDeclaration[_] = StaticJavaParser.parseBodyDeclaration(fullText) + /** Parses this element as a class body declaration (e.g. a method or a + * field). + */ + def classBodyDeclaration(): BodyDeclaration[?] = + StaticJavaParser.parseBodyDeclaration(fullText) /** Parses this element as multiple class body declarations. */ - def classBodyDeclarations(): Seq[BodyDeclaration[_]] = - StaticJavaParser.parse(s"class C { $fullText }").getTypes.asScala.head.getMembers.asScala.to(Seq) + def classBodyDeclarations(): Seq[BodyDeclaration[?]] = + StaticJavaParser + .parse(s"class C { $fullText }") + .getTypes + .asScala + .head + .getMembers + .asScala + .to(Seq) /** Parses this element as multiple field declarations. */ def fieldDeclarations(): Seq[FieldDeclaration] = @@ -85,8 +102,11 @@ class Java private(elements: Seq[Java], text: String) extends BufferedContent[Ja def constructors(): Seq[ConstructorDeclaration] = classBodyDeclarations().map(_.asInstanceOf[ConstructorDeclaration]) - /** Parses this element as an interface body declaration (e.g. a method signature). */ - def interfaceBodyDeclaration(): BodyDeclaration[_] = StaticJavaParser.parseBodyDeclaration(fullText) + /** Parses this element as an interface body declaration (e.g. a method + * signature). + */ + def interfaceBodyDeclaration(): BodyDeclaration[?] = + StaticJavaParser.parseBodyDeclaration(fullText) /** Parses this element as a type (e.g. the in X foo = (X)bar). */ def tpe(): Type = StaticJavaParser.parseType(fullText) @@ -94,10 +114,13 @@ class Java private(elements: Seq[Java], text: String) extends BufferedContent[Ja /** Helper for Java utility methods. */ object Java { + /** Creates a Java fragment with initial content specified. */ def apply(text: String): Java = new Java(text) - /** Creates a Java fragment with initial content from the given `text` separated by `separator`. */ + /** Creates a Java fragment with initial content from the given `text` + * separated by `separator`. + */ def apply(text: Seq[String], separator: String = ";"): Java = { apply(text.mkString(separator)) } @@ -106,19 +129,22 @@ object Java { def apply(node: Node): Java = Java(node.toString) /** Creates a Java fragment with initial content from the asts `nodes`. */ - def apply(nodes: Seq[Node]): Java = new Java(Seq(nodes map apply : _*)) + def apply(nodes: Seq[Node]): Java = new Java(Seq((nodes.map(apply))*)) } object JavaFormat extends Format[Java] { + /** Integrates `text` without performing any escaping process. * - * @param text Text to integrate + * @param text + * Text to integrate */ def raw(text: String): Java = Java(text) /** Escapes `text` using Java String rules. * - * @param text Text to integrate + * @param text + * Text to integrate */ def escape(text: String): Java = Java(StringEscapeUtils.escapeJava(text)) diff --git a/src/main/scala/org/combinators/templating/twirl/Python.scala b/src/main/scala/org/combinators/templating/twirl/Python.scala index 5ecf52b..5296c01 100644 --- a/src/main/scala/org/combinators/templating/twirl/Python.scala +++ b/src/main/scala/org/combinators/templating/twirl/Python.scala @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 Jan Bessai + * Copyright 2017-2025 Jan Bessai * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,12 +20,11 @@ import org.apache.commons.text.StringEscapeUtils import play.twirl.api.{BufferedContent, Format, Formats} import scala.collection.immutable -import scala.collection.compat._ -/** - * A Python fragment. +/** A Python fragment. */ -class Python private(elements: immutable.Seq[Python], text: String) extends BufferedContent[Python](elements, text) { +class Python private (elements: immutable.Seq[Python], text: String) + extends BufferedContent[Python](elements, text) { def this(text: String) = this(Nil, Formats.safe(text)) def this(elements: immutable.Seq[Python]) = this(elements, "") @@ -49,33 +48,36 @@ class Python private(elements: immutable.Seq[Python], text: String) extends Buff def getCode: String = fullText } -/** - * Helper for Python utility methods. +/** Helper for Python utility methods. */ object Python { + /** Creates a Python fragment with initial content specified. */ def apply(text: String): Python = { new Python(text) } - /** Creates a Python fragment with initial content from the given `text` separated by `separator`. */ + /** Creates a Python fragment with initial content from the given `text` + * separated by `separator`. + */ def apply(text: Seq[String], separator: String = ";"): Python = { apply(text.mkString(separator)) } } object PythonFormat extends Format[Python] { - /** - * Integrates `text` without performing any escaping process. + + /** Integrates `text` without performing any escaping process. * - * @param text Text to integrate + * @param text + * Text to integrate */ def raw(text: String): Python = Python(text) - /** - * Escapes `text` using Python String rules. + /** Escapes `text` using Python String rules. * - * @param text Text to integrate + * @param text + * Text to integrate */ def escape(text: String): Python = Python(StringEscapeUtils.escapeJava(text)) @@ -86,4 +88,3 @@ object PythonFormat extends Format[Python] { def fill(elements: immutable.Seq[Python]): Python = new Python(elements) } - diff --git a/src/test/java-templates/org/combinators/templating/JavaTemplateTest.scala.java b/src/test/java-templates/org/combinators/templating/JavaTemplateTest.scala.java index b037f76..a9a8f06 100644 --- a/src/test/java-templates/org/combinators/templating/JavaTemplateTest.scala.java +++ b/src/test/java-templates/org/combinators/templating/JavaTemplateTest.scala.java @@ -5,12 +5,12 @@ someString: Expression, qualifiedName: Name, nameExpression: NameExpr, - singleDecl: BodyDeclaration[_], - multiDecls: Seq[BodyDeclaration[_]], + singleDecl: BodyDeclaration[?], + multiDecls: Seq[BodyDeclaration[?]], fieldDeclarations: Seq[FieldDeclaration], methodDeclarations: Seq[MethodDeclaration], constructors: Seq[ConstructorDeclaration], - interfaceMethod: BodyDeclaration[_], + interfaceMethod: BodyDeclaration[?], tpe: Type) @Java(imp) @@ -44,4 +44,4 @@ public static void messUpEnviornment() { public interface FooI { @Java(interfaceMethod) -} \ No newline at end of file +} diff --git a/src/test/scala/org/combinators/templating/persistable/JavaPersistableTest.scala b/src/test/scala/org/combinators/templating/persistable/JavaPersistableTest.scala index 59c0620..7d289c3 100644 --- a/src/test/scala/org/combinators/templating/persistable/JavaPersistableTest.scala +++ b/src/test/scala/org/combinators/templating/persistable/JavaPersistableTest.scala @@ -1,3 +1,19 @@ +/* + * Copyright 2017-2025 Jan Bessai + * + * 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.combinators.templating.persistable import java.nio.file.Paths @@ -7,42 +23,67 @@ import JavaPersistable._ import org.combinators.templating.twirl.Java import org.scalatest._ +import funspec._ -class JavaPersistableTest extends FunSpec { +class JavaPersistableTest extends AnyFunSpec { val className = "Foo" val classText = s"import whatever; class $className {}" - val persistableInstance: Persistable.Aux[CompilationUnit] = JavaPersistable.apply + val persistableInstance: Persistable.Aux[CompilationUnit] = + JavaPersistable.apply val pathPrefix = Seq("src", "main", "java") describe("Persisting a Java compilation unit") { describe(s"when it contains only one class $className and no package") { it(s"should use 'src/main/java/$className.java' as path") { val expectedPathComponents = pathPrefix :+ s"$className.java" - assert(persistableInstance.path(Java(classText).compilationUnit()) - == Paths.get(expectedPathComponents.head, expectedPathComponents.tail:_*)) + assert( + persistableInstance.path(Java(classText).compilationUnit()) + == Paths.get( + expectedPathComponents.head, + expectedPathComponents.tail* + ) + ) } } describe("when it contains multiple classes and interfaces") { it("should use the name of the first class to determine the path") { val otherClassText = "interface FooI {}\n class Bar {}" val expectedPathComponents = pathPrefix :+ s"$className.java" - assert(persistableInstance.path(Java(Seq(classText, otherClassText).mkString("\n")).compilationUnit()) - == Paths.get(expectedPathComponents.head, expectedPathComponents.tail:_*)) + assert( + persistableInstance.path( + Java(Seq(classText, otherClassText).mkString("\n")) + .compilationUnit() + ) + == Paths.get( + expectedPathComponents.head, + expectedPathComponents.tail* + ) + ) } } describe("when it contains a package declaration") { it("should prefix the path with a directory structure for the package") { val packages = Seq("foo", "bar") val packagesText = s"package ${packages.mkString(".")};" - val expectedPathComponents = pathPrefix ++ packages :+ s"$className.java" - assert(persistableInstance.path(Java(Seq(packagesText, classText).mkString("\n")).compilationUnit()) - == Paths.get(expectedPathComponents.head, expectedPathComponents.tail:_*)) + val expectedPathComponents = + pathPrefix ++ packages :+ s"$className.java" + assert( + persistableInstance.path( + Java(Seq(packagesText, classText).mkString("\n")).compilationUnit() + ) + == Paths.get( + expectedPathComponents.head, + expectedPathComponents.tail* + ) + ) } } it("should store text that parses back to an equal CompilationUnit") { val originalUnit = Java(classText).compilationUnit() - assert(Java(new String(persistableInstance.rawText(originalUnit))).compilationUnit() == originalUnit) + assert( + Java(new String(persistableInstance.rawText(originalUnit))) + .compilationUnit() == originalUnit + ) } } } - diff --git a/src/test/scala/org/combinators/templating/persistable/PersistableTest.scala b/src/test/scala/org/combinators/templating/persistable/PersistableTest.scala index f8fb4ed..19ec9f8 100644 --- a/src/test/scala/org/combinators/templating/persistable/PersistableTest.scala +++ b/src/test/scala/org/combinators/templating/persistable/PersistableTest.scala @@ -1,17 +1,37 @@ +/* + * Copyright 2017-2025 Jan Bessai + * + * 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.combinators.templating.persistable import java.nio.file.{FileAlreadyExistsException, Files, Path, Paths} import org.scalatest._ +import funspec._ -class PersistableTest extends fixture.FunSpec with TempDirectoryFixture with GivenWhenThen { +class PersistableTest + extends FixtureAnyFunSpec + with TempDirectoryFixture + with GivenWhenThen { val persistable: Persistable.Aux[String] = new Persistable { override type T = String override def rawText(elem: T): Array[Byte] = elem.getBytes override def path(elem: T): Path = Paths.get(elem) } describe("Persisting a String to a file named by its content") { - it("should create a file named by its content") { tmpDir: Path => + it("should create a file named by its content") { (tmpDir: Path) => Given("an element to persist") val elementToPersist = "test" @@ -23,18 +43,24 @@ class PersistableTest extends fixture.FunSpec with TempDirectoryFixture with Giv assert(Files.exists(expectedPath)) And("the file should have exactly the specified contents") - assert(Files.readAllBytes(expectedPath).sameElements(elementToPersist.getBytes)) + assert( + Files.readAllBytes(expectedPath).sameElements(elementToPersist.getBytes) + ) And("trying to persist the same element again should raise an exception") - assertThrows[FileAlreadyExistsException](persistable.persist(tmpDir.toAbsolutePath, elementToPersist)) + assertThrows[FileAlreadyExistsException]( + persistable.persist(tmpDir.toAbsolutePath, elementToPersist) + ) - Then("it should not produce the exception when overwrite semantics is specified") + Then( + "it should not produce the exception when overwrite semantics is specified" + ) persistable.persistOverwriting(tmpDir.toAbsolutePath, elementToPersist) } } describe("Persisting an element that specifies a subdirectory") { - it("should create a subdirectory") { tmpDir: Path => + it("should create a subdirectory") { (tmpDir: Path) => Given("an element to persist") val elementToPersistInSubdir = Paths.get("foo", "test").toString @@ -51,13 +77,24 @@ class PersistableTest extends fixture.FunSpec with TempDirectoryFixture with Giv assert(Files.exists(expectedFileInSubdir)) And("the file should have exactly the specified contents") - assert(Files.readAllBytes(expectedFileInSubdir).sameElements(elementToPersistInSubdir.getBytes)) + assert( + Files + .readAllBytes(expectedFileInSubdir) + .sameElements(elementToPersistInSubdir.getBytes) + ) And("trying to persist the same element again should raise an exception") - assertThrows[FileAlreadyExistsException](persistable.persist(tmpDir.toAbsolutePath, elementToPersistInSubdir)) + assertThrows[FileAlreadyExistsException]( + persistable.persist(tmpDir.toAbsolutePath, elementToPersistInSubdir) + ) - Then("it should not produce the exception when overwrite semantics is specified") - persistable.persistOverwriting(tmpDir.toAbsolutePath, elementToPersistInSubdir) + Then( + "it should not produce the exception when overwrite semantics is specified" + ) + persistable.persistOverwriting( + tmpDir.toAbsolutePath, + elementToPersistInSubdir + ) } } } diff --git a/src/test/scala/org/combinators/templating/persistable/PythonWithPathPersistableTest.scala b/src/test/scala/org/combinators/templating/persistable/PythonWithPathPersistableTest.scala index 3cc9828..7d31579 100644 --- a/src/test/scala/org/combinators/templating/persistable/PythonWithPathPersistableTest.scala +++ b/src/test/scala/org/combinators/templating/persistable/PythonWithPathPersistableTest.scala @@ -1,3 +1,19 @@ +/* + * Copyright 2017-2025 Jan Bessai + * + * 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.combinators.templating.persistable import java.nio.file.{FileAlreadyExistsException, Files, Path, Paths} @@ -5,34 +21,49 @@ import java.nio.file.{FileAlreadyExistsException, Files, Path, Paths} import PythonWithPathPersistable._ import org.combinators.templating.twirl.Python import org.scalatest._ +import funspec._ -class PythonWithPathPersistableTest extends fixture.FunSpec with TempDirectoryFixture with GivenWhenThen { - val persistable: PythonWithPathPersistable.Aux[PythonWithPath] = PythonWithPathPersistable.apply +class PythonWithPathPersistableTest + extends FixtureAnyFunSpec + with TempDirectoryFixture + with GivenWhenThen { + val persistable: PythonWithPathPersistable.Aux[PythonWithPath] = + PythonWithPathPersistable.apply describe("Persisting a piece of Python code to a file") { - it("should create a file named by its content") { tmpDir: Path => + it("should create a file named by its content") { (tmpDir: Path) => Given("an element to persist") val elementToPersist: PythonWithPath = PythonWithPath( Python(s"""class Foo: | pass """.stripMargin), - Paths.get("bar/test.py")) + Paths.get("bar/test.py") + ) When("persisting it") persistable.persist(tmpDir.toAbsolutePath, elementToPersist) Then("its corresponding file should exist") - val expectedPath = tmpDir.toAbsolutePath.resolve(elementToPersist.persistTo) + val expectedPath = + tmpDir.toAbsolutePath.resolve(elementToPersist.persistTo) assert(Files.exists(expectedPath)) And("the file should have exactly the specified contents") - assert(Files.readAllBytes(expectedPath).sameElements(elementToPersist.code.getCode.getBytes)) + assert( + Files + .readAllBytes(expectedPath) + .sameElements(elementToPersist.code.getCode.getBytes) + ) And("trying to persist the same element again should raise an exception") - assertThrows[FileAlreadyExistsException](persistable.persist(tmpDir.toAbsolutePath, elementToPersist)) + assertThrows[FileAlreadyExistsException]( + persistable.persist(tmpDir.toAbsolutePath, elementToPersist) + ) - Then("it should not produce the exception when overwrite semantics is specified") + Then( + "it should not produce the exception when overwrite semantics is specified" + ) persistable.persistOverwriting(tmpDir.toAbsolutePath, elementToPersist) } } diff --git a/src/test/scala/org/combinators/templating/persistable/ResourcePersistableTest.scala b/src/test/scala/org/combinators/templating/persistable/ResourcePersistableTest.scala index 60c7f1a..8154662 100644 --- a/src/test/scala/org/combinators/templating/persistable/ResourcePersistableTest.scala +++ b/src/test/scala/org/combinators/templating/persistable/ResourcePersistableTest.scala @@ -1,35 +1,70 @@ +/* + * Copyright 2017-2025 Jan Bessai + * + * 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.combinators.templating.persistable import java.nio.file.{FileAlreadyExistsException, Files, Path, Paths} import org.scalatest._ +import funspec._ -class ResourcePersistableTest extends fixture.FunSpec with TempDirectoryFixture with GivenWhenThen { +class ResourcePersistableTest + extends FixtureAnyFunSpec + with TempDirectoryFixture + with GivenWhenThen { - val persistableInstance: Persistable.Aux[BundledResource] = ResourcePersistable.apply + val persistableInstance: Persistable.Aux[BundledResource] = + ResourcePersistable.apply describe("Persisting a picture from the resources folder") { - it("should create a file named by its content") { tmpDir: Path => + it("should create a file named by its content") { (tmpDir: Path) => Given("a resource to persist") val elementToPersist: BundledResource = - BundledResource("res/GammaMtau.png", Paths.get("test", "path", "picture.png"), getClass) + BundledResource( + "res/GammaMtau.png", + Paths.get("test", "path", "picture.png"), + getClass() + ) When("persisting it") persistableInstance.persist(tmpDir.toAbsolutePath, elementToPersist) Then("its corresponding file should exist") - val expectedPath: Path = tmpDir.toAbsolutePath.resolve(elementToPersist.persistTo) + val expectedPath: Path = + tmpDir.toAbsolutePath.resolve(elementToPersist.persistTo) assert(Files.exists(expectedPath)) And("the file should have exactly the specified contents") - val resourceBytes = Files.readAllBytes(Paths.get(getClass.getResource("res/GammaMtau.png").toURI)) + val resourceBytes = Files.readAllBytes( + Paths.get(getClass.getResource("res/GammaMtau.png").toURI) + ) assert(Files.readAllBytes(expectedPath).sameElements(resourceBytes)) And("trying to persist the same element again should raise an exception") - assertThrows[FileAlreadyExistsException](persistableInstance.persist(tmpDir.toAbsolutePath, elementToPersist)) + assertThrows[FileAlreadyExistsException]( + persistableInstance.persist(tmpDir.toAbsolutePath, elementToPersist) + ) - Then("it should not produce the exception when overwrite semantics is specified") - persistableInstance.persistOverwriting(tmpDir.toAbsolutePath, elementToPersist) + Then( + "it should not produce the exception when overwrite semantics is specified" + ) + persistableInstance.persistOverwriting( + tmpDir.toAbsolutePath, + elementToPersist + ) } } -} \ No newline at end of file +} diff --git a/src/test/scala/org/combinators/templating/persistable/TempDirectoryFixture.scala b/src/test/scala/org/combinators/templating/persistable/TempDirectoryFixture.scala index 55baeb0..38984a8 100644 --- a/src/test/scala/org/combinators/templating/persistable/TempDirectoryFixture.scala +++ b/src/test/scala/org/combinators/templating/persistable/TempDirectoryFixture.scala @@ -1,13 +1,30 @@ +/* + * Copyright 2017-2025 Jan Bessai + * + * 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.combinators.templating.persistable import java.nio.file.{Files, Path} import org.apache.commons.io.FileUtils -import org.scalatest.{Outcome, fixture} +import org.scalatest.{funspec, Outcome} +import funspec._ -trait TempDirectoryFixture { self: fixture.FunSpec => +trait TempDirectoryFixture { self: FixtureAnyFunSpec => type FixtureParam = Path - def withFixture(test: OneArgTest): Outcome = { + override def withFixture(test: OneArgTest): Outcome = { val tmpDir = Files.createTempDirectory("inhabitants") try withFixture(test.toNoArgTest(tmpDir)) finally FileUtils.deleteDirectory(tmpDir.toFile) diff --git a/src/test/scala/org/combinators/templating/twirl/JavaTest.scala b/src/test/scala/org/combinators/templating/twirl/JavaTest.scala index 868208d..5dd01d6 100644 --- a/src/test/scala/org/combinators/templating/twirl/JavaTest.scala +++ b/src/test/scala/org/combinators/templating/twirl/JavaTest.scala @@ -1,15 +1,36 @@ +/* + * Copyright 2017-2025 Jan Bessai + * + * 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.combinators.templating.twirl import com.github.javaparser.ast.ImportDeclaration import com.github.javaparser.ast.`type`.Type -import com.github.javaparser.ast.body.{BodyDeclaration, ConstructorDeclaration, FieldDeclaration, MethodDeclaration} +import com.github.javaparser.ast.body.{ + BodyDeclaration, + ConstructorDeclaration, + FieldDeclaration, + MethodDeclaration +} import com.github.javaparser.ast.expr._ import com.github.javaparser.ast.stmt.Statement import org.scalatest._ +import funspec._ import scala.collection.immutable._ -import scala.collection.compat._ -class JavaTest extends FunSpec { +class JavaTest extends AnyFunSpec { val expected: String = """ |import bar.Bar; @@ -78,28 +99,28 @@ class JavaTest extends FunSpec { |} """.stripMargin - val importDecl: ImportDeclaration = Java("import bar.Bar;").importDeclaration() + val importDecl: ImportDeclaration = + Java("import bar.Bar;").importDeclaration() val className: SimpleName = Java("YYY$_ZZZ").simpleName() - val singleStatement: Statement = Java(s"""System.out.println("never do this in practice!");""").statement() - val multiStatements: Seq[Statement] = Java( - s""" + val singleStatement: Statement = + Java(s"""System.out.println("never do this in practice!");""").statement() + val multiStatements: Seq[Statement] = Java(s""" |int x = 1; // I don't know |for (int y = 10; y > x; y--) { | System.out.println("why I do this"); |}""".stripMargin).statements() - val someString: StringLiteralExpr = Java(""""Ei cän \" dö Ünicöð€"""").expression() + val someString: StringLiteralExpr = + Java(""""Ei cän \" dö Ünicöð€"""").expression() val tpe: Type = Java("Hululu.Lalala[][]").tpe() val fieldDeclarations: Seq[FieldDeclaration] = - Java( - s""" + Java(s""" |static X xoo = null; |Y yoo = new Yoo(); |Z[] zoos;""".stripMargin).fieldDeclarations() val name: Name = Java("some.EnvironmentClass.xoo").name() val nameExpr: NameExpr = Java("xoo").nameExpression() val constructors: Seq[ConstructorDeclaration] = - Java( - s""" + Java(s""" |/** By default do crazyness. */ |public YYY$$_ZZZ() { | System.disco(); @@ -111,23 +132,20 @@ class JavaTest extends FunSpec { | super(zs); | System.disco(); |}""".stripMargin).constructors() - val singleDecl: BodyDeclaration[_] = - Java( - s""" + val singleDecl: BodyDeclaration[?] = + Java(s""" |public static void main(String[] args) { | System.out.println("The application has crashed"); | System.out.println("Never run this application again"); |}""".stripMargin).classBodyDeclaration() - val multiDecls: Seq[BodyDeclaration[_]] = - Java( - s""" + val multiDecls: Seq[BodyDeclaration[?]] = + Java(s""" |public static volatile String gargh = "GAAAAAAARRRG!!"; |@nobodyunderstands public int getReason() { return reason; } |public int reason = 42;""".stripMargin).classBodyDeclarations() val methodDecls: Seq[MethodDeclaration] = - Java( - s""" + Java(s""" |private void hiddenEffect() { | System.evil(); | } @@ -135,29 +153,35 @@ class JavaTest extends FunSpec { | System.out.println(withThisArg); | hiddenEffect(); // I break my contract }:-> | }""".stripMargin).methodDeclarations() - val interfaceMethod: BodyDeclaration[_] = - Java("public default void doFoos(YYY$_ZZZ x) { System.out.println(x.toString()); }").interfaceBodyDeclaration() + val interfaceMethod: BodyDeclaration[?] = + Java( + "public default void doFoos(YYY$_ZZZ x) { System.out.println(x.toString()); }" + ).interfaceBodyDeclaration() describe("Rendering a Java template with lots of stuff and strings in it") { - val rendered: JavaFormat.Appendable = org.combinators.templating.java.JavaTemplateTest.render( - imp = importDecl, - className = className, - singleStatement = singleStatement, - multiStatements = multiStatements, - someString = someString, - qualifiedName = name, - nameExpression = nameExpr, - singleDecl = singleDecl, - multiDecls = multiDecls, - fieldDeclarations = fieldDeclarations, - methodDeclarations = methodDecls, - constructors = constructors, - interfaceMethod = interfaceMethod, - tpe = tpe) + val rendered: JavaFormat.Appendable = + org.combinators.templating.java.JavaTemplateTest.render( + imp = importDecl, + className = className, + singleStatement = singleStatement, + multiStatements = multiStatements, + someString = someString, + qualifiedName = name, + nameExpression = nameExpr, + singleDecl = singleDecl, + multiDecls = multiDecls, + fieldDeclarations = fieldDeclarations, + methodDeclarations = methodDecls, + constructors = constructors, + interfaceMethod = interfaceMethod, + tpe = tpe + ) describe("when parsing it") { val parsedResult = rendered.compilationUnit() it("should be equal to the expected result") { - assert(Java(expected).compilationUnit().toString == parsedResult.toString) + assert( + Java(expected).compilationUnit().toString == parsedResult.toString + ) } } } diff --git a/src/test/scala/org/combinators/templating/twirl/PythonTest.scala b/src/test/scala/org/combinators/templating/twirl/PythonTest.scala index 01084e1..2b63879 100644 --- a/src/test/scala/org/combinators/templating/twirl/PythonTest.scala +++ b/src/test/scala/org/combinators/templating/twirl/PythonTest.scala @@ -1,8 +1,25 @@ +/* + * Copyright 2017-2025 Jan Bessai + * + * 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.combinators.templating.twirl import org.scalatest._ +import funspec._ -class PythonTest extends FunSpec { +class PythonTest extends AnyFunSpec { val expected: String = """ |class Foo(object): @@ -26,14 +43,12 @@ class PythonTest extends FunSpec { val clsName: Python = Python("Foo") val body: Python = - Python( - """self.blah = "eggs!" + Python("""self.blah = "eggs!" |if true: | pass |else: | pass""".stripMargin) - val bodyTight: Python = Python( - """if false: + val bodyTight: Python = Python("""if false: | pass |else: | pass""".stripMargin) @@ -44,7 +59,8 @@ class PythonTest extends FunSpec { clsName = clsName, text = text, body = body, - bodyTight = bodyTight) + bodyTight = bodyTight + ) it("should produce exactly the expected substitution") { assert(expected.trim == rendered.getCode.trim) } diff --git a/travis/secrets.tar.enc b/travis/secrets.tar.enc deleted file mode 100644 index a3bac9e..0000000 Binary files a/travis/secrets.tar.enc and /dev/null differ