Skip to content

Commit

Permalink
Make code generator tests usable from other slick-extensions:
Browse files Browse the repository at this point in the history
slick-testkit now depends on slick-codegen and provides the
TestCodeGenerator and TestCodeRunner types which provide the tools
needed to generate and run code generator tests.
  • Loading branch information
szeiger committed Feb 20, 2015
1 parent 25370cb commit 7f0f62f
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 111 deletions.
2 changes: 1 addition & 1 deletion project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ object SlickBuild extends Build {
//test <<= Seq(test in Test, test in DocTest).dependOn,
//concurrentRestrictions += Tags.limitSum(1, Tags.Test, Tags.ForkedTestGroup),
//concurrentRestrictions in Global += Tags.limit(Tags.Test, 1),
) dependsOn(slickProject, slickCodegenProject % "test->compile", slickDirectProject % "test->compile")
) dependsOn(slickProject, slickCodegenProject % "compile->compile", slickDirectProject % "test->compile")

lazy val slickCodegenProject = Project(id = "codegen", base = file("slick-codegen"),
settings = Defaults.coreDefaultSettings ++ sdlcSettings ++ sharedSettings ++ extTarget("codegen") ++ Seq(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package slick.test.codegen
import java.io.File
import java.sql.Blob

import com.typesafe.slick.testkit.util.{InternalJdbcTestDB, StandardTestDBs, JdbcTestDB}
import com.typesafe.slick.testkit.util.{TestCodeGenerator, InternalJdbcTestDB, StandardTestDBs, JdbcTestDB}

import scala.concurrent.{Future, Await}
import scala.concurrent.duration.Duration
Expand All @@ -18,7 +18,10 @@ import slick.jdbc.meta.MTable
import slick.model.Model

/** Generates files for GeneratedCodeTest */
object GenerateMainSources {
object GenerateMainSources extends TestCodeGenerator {
def packageName = "slick.test.codegen.generated"
def defaultTestCode(c: Config): String = "slick.test.codegen.GeneratedCodeTest.test" + c.objectName

lazy val configurations = Seq(
new Config("CG1", StandardTestDBs.H2Mem, "H2Mem", Seq("/dbs/h2.sql")),
new Config("CG2", StandardTestDBs.HsqldbMem, "HsqldbMem", Seq("/dbs/hsqldb.sql")),
Expand Down Expand Up @@ -105,83 +108,6 @@ val SimpleA = CustomTyping.SimpleA
new UUIDConfig("Postgres2", StandardTestDBs.Postgres, "Postgres", Seq("/dbs/uuid.sql"))
)

def packageName = "slick.test.codegen.generated"

def main(args: Array[String]): Unit = try {
val clns = configurations.flatMap(_.generate(args(0)).toSeq)
new OutputHelpers {
def indent(code: String): String = code
def code: String = ""
}.writeStringToFile(
s"""
|package $packageName
|object AllTests {
| val clns = Seq(${clns.map("\"" + _ + "\"").mkString(", ")})
|}
""".stripMargin, args(0), packageName, "AllTests.scala"
)
} catch { case ex: Throwable =>
ex.printStackTrace(System.err)
System.exit(1)
}

class Config(val objectName: String, val tdb: JdbcTestDB, tdbName: String, initScripts: Seq[String]) { self =>

def slickDriver = tdb.driver.getClass.getName.replaceAll("\\$", "")

def fullTdbName = StandardTestDBs.getClass.getName.replaceAll("\\$", "") + "." + tdbName

def generate(dir: String): Option[String] = if(tdb.isEnabled || tdb.isInstanceOf[InternalJdbcTestDB]) {
tdb.cleanUpBefore()
try {
var init: DBIO[Any] = DBIO.successful(())
var current: String = null
initScripts.foreach { initScript =>
import tdb.driver.api._
Source.fromURL(self.getClass.getResource(initScript))(Codec.UTF8).getLines().foreach { s =>
if(current eq null) current = s else current = current + "\n" + s
if(s.trim.endsWith(";")) {
init = init >> sqlu"#$current"
current = null
}
}
if(current ne null) init = init >> sqlu"#$current"
}
val db = tdb.createDB()
try {
val m = Await.result(db.run((init >> generator).withPinnedSession), Duration.Inf)
m.writeToFile(profile=slickDriver, folder=dir, pkg=packageName, objectName, fileName=objectName+".scala" )
} finally db.close
}
finally tdb.cleanUpAfter()
Some(s"$packageName.$objectName")
} else None

def generator: DBIO[SourceCodeGenerator] =
tdb.driver.createModel(ignoreInvalidDefaults=false).map(new MyGen(_))

def testCode: String = "slick.test.codegen.GeneratedCodeTest.test" + objectName

class MyGen(model:Model) extends SourceCodeGenerator(model) {
override def entityName = sqlName => {
val baseName = super.entityName(sqlName)
if(baseName.dropRight(3).last == 's') baseName.dropRight(4)
else baseName
}
override def parentType = Some("slick.test.codegen.GeneratedCodeTest.TestCase")
override def code = {
s"""
|lazy val tdb = $fullTdbName
|def test = {
| import org.junit.Assert._
| import scala.concurrent.ExecutionContext.Implicits.global
| $testCode
|}
""".stripMargin + super.code
}
}
}

//Unified UUID config
class UUIDConfig(objectName: String, tdb: JdbcTestDB, tdbName: String, initScripts: Seq[String])
extends Config(objectName, tdb, tdbName, initScripts) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package com.typesafe.slick.testkit.util

import scala.concurrent.Await
import scala.concurrent.duration.Duration
import scala.concurrent.ExecutionContext.Implicits.global
import scala.io.{Codec, Source}

import java.util.concurrent.ExecutionException

import slick.codegen.{OutputHelpers, SourceCodeGenerator}
import slick.dbio._
import slick.model.Model

import org.junit.Test

trait TestCodeGenerator {
def packageName: String
def defaultTestCode(c: Config): String
def configurations: Seq[Config]
def computeFullTdbName(tdbName: String) = StandardTestDBs.getClass.getName.replaceAll("\\$", "") + "." + tdbName

def main(args: Array[String]): Unit = try {
val clns = configurations.flatMap(_.generate(args(0)).toSeq)
new OutputHelpers {
def indent(code: String): String = code
def code: String = ""
}.writeStringToFile(
s"""
|package $packageName
|object AllTests extends com.typesafe.slick.testkit.util.TestCodeRunner.AllTests {
| val clns = Seq(${clns.map("\"" + _ + "\"").mkString(", ")})
|}
""".stripMargin, args(0), packageName, "AllTests.scala"
)
} catch { case ex: Throwable =>
ex.printStackTrace(System.err)
System.exit(1)
}

class Config(val objectName: String, val tdb: JdbcTestDB, tdbName: String, initScripts: Seq[String]) { self =>
def useSingleLineStatements = false

def slickDriver = tdb.driver.getClass.getName.replaceAll("\\$", "")

def fullTdbName = computeFullTdbName(tdbName)

def generate(dir: String): Option[String] = if(tdb.isEnabled || tdb.isInstanceOf[InternalJdbcTestDB]) {
tdb.cleanUpBefore()
try {
var init: DBIO[Any] = DBIO.successful(())
var current: String = null
initScripts.foreach { initScript =>
import tdb.driver.api._
Source.fromURL(self.getClass.getResource(initScript))(Codec.UTF8).getLines().foreach { s =>
if(current eq null) current = s else current = current + "\n" + s
if(s.trim.endsWith(";")) {
if(useSingleLineStatements) {
current = current.substring(0, current.length-1)
current = current.replace("\r", "").replace('\n', ' ')
}
init = init >> sqlu"#$current"
current = null
}
}
if(current ne null) {
if(useSingleLineStatements) current = current.replace("\r", "").replace('\n', ' ')
init = init >> sqlu"#$current"
}
}
val db = tdb.createDB()
try {
val m = Await.result(db.run((init >> generator).withPinnedSession), Duration.Inf)
m.writeToFile(profile=slickDriver, folder=dir, pkg=packageName, objectName, fileName=objectName+".scala" )
} finally db.close
}
finally tdb.cleanUpAfter()
Some(s"$packageName.$objectName")
} else None

def generator: DBIO[SourceCodeGenerator] =
tdb.driver.createModel(ignoreInvalidDefaults=false).map(new MyGen(_))

def testCode: String = defaultTestCode(this)

class MyGen(model:Model) extends SourceCodeGenerator(model) {
override def entityName = sqlName => {
val baseName = super.entityName(sqlName)
if(baseName.dropRight(3).last == 's') baseName.dropRight(4)
else baseName
}
override def parentType = Some("com.typesafe.slick.testkit.util.TestCodeRunner.TestCase")
override def code = {
s"""
|lazy val tdb = $fullTdbName
|def test = {
| import org.junit.Assert._
| import scala.concurrent.ExecutionContext.Implicits.global
| $testCode
|}
""".stripMargin + super.code
}
}
}
}

class TestCodeRunner(tests: TestCodeRunner.AllTests) {
def run(cln: String): Unit = {
val t = Class.forName(cln+"$").getField("MODULE$").get(null).asInstanceOf[TestCodeRunner.TestCase]
val tdb = t.tdb
println(s"Running test $cln on ${tdb.confName}")
if(tdb.isEnabled) {
tdb.cleanUpBefore()
try {
val a = t.test
val db = tdb.createDB()
try Await.result(db.run(a.withPinnedSession), Duration.Inf)
catch { case e: ExecutionException => throw e.getCause }
finally db.close()
} finally tdb.cleanUpAfter()
} else println("- Test database is disabled")
}

@Test def allTests = tests.clns.foreach(run)
}

object TestCodeRunner {
trait AllTests {
def clns: Seq[String]
}
trait TestCase {
def test: slick.dbio.DBIO[Any]
def tdb: JdbcTestDB
}
}
Original file line number Diff line number Diff line change
@@ -1,44 +1,16 @@
package slick.test.codegen

import java.util.concurrent.ExecutionException

import org.junit.Test
import org.junit.Assert._
import scala.concurrent.Await
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.Duration
import slick.jdbc.meta.MTable
import slick.ast.{Node, Select}
import slick.test.codegen.generated._
import com.typesafe.slick.testkit.util.JdbcTestDB
import com.typesafe.slick.testkit.util.{TestCodeRunner, JdbcTestDB}
import org.junit.Assert._

/** Test files generated by CodeGeneratorTest */
class GeneratedCodeTest {
def run(cln: String): Unit = {
val t = Class.forName(cln+"$").getField("MODULE$").get(null).asInstanceOf[GeneratedCodeTest.TestCase]
val tdb = t.tdb
println(s"Running test $cln on ${tdb.confName}")
if(tdb.isEnabled) {
tdb.cleanUpBefore()
try {
val a = t.test
val db = tdb.createDB()
try Await.result(db.run(a.withPinnedSession), Duration.Inf)
catch { case e: ExecutionException => throw e.getCause }
finally db.close()
} finally tdb.cleanUpAfter()
} else println("- Test database is disabled")
}

@Test def allTests = AllTests.clns.foreach(run)
}
class GeneratedCodeTest extends TestCodeRunner(AllTests)

object GeneratedCodeTest {
trait TestCase {
def test: slick.dbio.DBIO[Any]
def tdb: JdbcTestDB
}

def testCG1 = {
import CG1._
import tdb.driver.api._
Expand Down

0 comments on commit 7f0f62f

Please sign in to comment.