Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Commit

Permalink
Merge pull request #2 from zio/build-testing-infra
Browse files Browse the repository at this point in the history
Enhance testing infrastructure
  • Loading branch information
deusaquilus authored Jan 12, 2023
2 parents 2f93bf9 + 039ca2a commit 235b48b
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 66 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
- name: Cache scala dependencies
uses: coursier/cache-action@v6
- name: Run tests
run: sbt compile
run: sbt test

ci:
runs-on: ubuntu-20.04
Expand Down
129 changes: 110 additions & 19 deletions src/test/scala/ZioDirectMacroSupportTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import org.jetbrains.plugins.scala.ScalaVersion
import org.jetbrains.plugins.scala.base.libraryLoaders.{IvyManagedLoader, LibraryLoader}
import org.jetbrains.plugins.scala.components.libextensions.LibraryExtensionsManager
import org.jetbrains.plugins.scala.lang.macros.evaluator.ScalaMacroTypeable
import org.jetbrains.plugins.scala.lang.typeInference.TypeInferenceTestBase
import org.jetbrains.plugins.scala.lang.typeInference.{TypeInferenceTestBase, WrappingContext}
import org.junit.Assert.assertTrue

import java.io.File
Expand Down Expand Up @@ -41,35 +41,126 @@ class ZioDirectMacroSupportTest extends TypeInferenceTestBase {
}
}

def testDummyExampleSuccess(): Unit = {
implicit val wrappingContext = WrappingContext(
"""|import zio._
|import zio.direct._
|import java.sql.SQLException
|
|case class ConfigA(value: String)
|case class ConfigB(value: String)
|case class ConfigC(value: String)
|case class ConfigD(value: String)
|case class ConfigE(value: String)
|
|class ErrorA extends Exception("A")
|class ErrorB extends Exception("B")
|class ErrorC extends Exception("C")
|class ErrorD extends Exception("D")
|class ErrorE extends Exception("E")
|
|""".stripMargin
)

def testServiceWithAttempt(): Unit = {
doTest(
s"""val value = "42" + 23
|${START}value$END
|//String
|""".stripMargin
s"""defer {
| val a = ZIO.service[ConfigA].run.value
| val b = ZIO.attempt("foo").run
| a
|}
|""".stripMargin,
"ZIO[ConfigA,Throwable,String]"
)
}

def test_defer_info(): Unit = {
doTest("""defer.info { val a = ZIO.service[ConfigA].run.value; a }""", "ZIO[ConfigA, Nothing, String")
}
def test_defer_tpe(): Unit = {
doTest("""defer.tpe { val a = ZIO.service[ConfigA].run.value; a }""", "ZIO[ConfigA, Nothing, String")
}
def test_defer_verbose(): Unit = {
doTest("""defer.verbose { val a = ZIO.service[ConfigA].run.value; a }""", "ZIO[ConfigA, Nothing, String")
}
def test_defer_verboseTree(): Unit = {
doTest("""defer.verboseTree { val a = ZIO.service[ConfigA].run.value; a }""", "ZIO[ConfigA, Nothing, String")
}

def testConfigAndErrorComposition(): Unit = {
doTest(
s"""defer {
| val a = ZIO.service[ConfigA].run.value
| ZIO.fail(new ErrorA).run
| val bc = {
| val b = ZIO.service[ConfigB].run.value
| ZIO.fail(new ErrorB).run
| val cc =
| defer {
| val c = ZIO.service[ConfigC].run.value
| ZIO.fail(new ErrorC).run
| c
| }
| b + cc.run
| }
| val d = ZIO.service[ConfigD].run.value
| ZIO.fail(new ErrorD).run
| a + d
|}
|""".stripMargin,
"ZIO[ConfigA with ConfigB with ConfigC with ConfigD, Exception, String]"
)
}

def testConfigAndErrorCompositionWithUnused(): Unit = {
doTest(
s"""defer {
| val a = ZIO.service[ConfigA].run.value
| if (a != "foo") ZIO.fail(new SQLException("foo")).run
| val b = ZIO.service[ConfigB].run.value
| if (b != "bar") ZIO.fail(new IllegalArgumentException("bar")).run
| val c = {
| val z = defer(123)
| z
| }
| a + "bar"
|}
|""".stripMargin,
"ZIO[ConfigA with ConfigB,Exception,String]"
)
}

def testDummyExampleFailure(): Unit = {
def testConfigAndErrorCompositionSameLine(): Unit = {
doTest(
s"""val value = "42" + 23
|${START}value$END
|//Short
|""".stripMargin
s"""val a = ZIO.service[ConfigA] *> ZIO.fail(new SQLException("foo")) *> ZIO.succeed("hello")
|val b = ZIO.service[ConfigB] *> ZIO.fail(new IllegalArgumentException("foo")) *> ZIO.succeed(123)
|defer { (a.run, b.run) }
|""".stripMargin,
"ZIO[ConfigA with ConfigB,Exception,(String, Int)]"
)
}

def testMacroSupport(): Unit = {
def testConfigAndErrorCompositionAndSameLine(): Unit = {
doTest(
s"""object Main {
| import zio._
| import zio.direct._
s"""val c = ZIO.service[ConfigC] *> ZIO.fail(new ErrorC) *> ZIO.succeed("hello")
|val d = ZIO.service[ConfigD] *> ZIO.fail(new ErrorD) *> ZIO.succeed(123)
|
| val value = defer(123)
| ${START}value$END
|defer {
| val a = ZIO.service[ConfigA].run.value
| ZIO.fail(new ErrorA).run
| val bc = {
| val b = ZIO.service[ConfigB].run.value
| ZIO.fail(new ErrorB).run
| val cc = defer {
| (c.run + b, d.run)
| }
| cc.run
| }
| val e = ZIO.service[ConfigE].run.value
| ZIO.fail(new ErrorE).run
| bc
|}
|//ZIO[Any, Nothing, 123]
|""".stripMargin
|""".stripMargin,
"ZIO[ConfigA with ConfigB with ConfigC with ConfigD with ConfigE, Exception, (String, Int)]"
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,12 @@ object SmartJDKLoader {
userHome + "/Library/Java/JavaVirtualMachines", // mac style
userHome + "/.jabba/jdk", // jabba (for github actions)
userHome + "/.jdks", // by default IDEA downloads JDKs here
userHome + "/.sdkman/candidates/java"
)
}

//NOTE: consider testing against JDK 17 by default in idea223.x
def getOrCreateJDK(languageLevel: LanguageLevel = LanguageLevel.JDK_11): Sdk = {
def getOrCreateJDK(languageLevel: LanguageLevel = LanguageLevel.JDK_17): Sdk = {
val jdkVersion = JavaSdkVersion.fromLanguageLevel(languageLevel)
val jdkName = jdkVersion.getDescription

Expand All @@ -82,6 +83,7 @@ object SmartJDKLoader {

private def createNewJdk(jdkVersion: JavaSdkVersion, jdkName: String): Sdk = {
val pathOption = SmartJDKLoader.discoverJDK(jdkVersion).map(_.getAbsolutePath)
println(s"======= Found Jdk Path: ${pathOption}")
Assert.assertTrue(s"Couldn't find $jdkVersion", pathOption.isDefined)

VfsRootAccess.allowRootAccess(ApplicationManager.getApplication, pathOption.get)
Expand All @@ -93,7 +95,7 @@ object SmartJDKLoader {

private def discoverJre(paths: Seq[String], jdkVersion: JavaSdkVersion): Option[File] = {
val versionMajor = jdkVersion.ordinal().toString
val versionStrings = Seq(s"1.$versionMajor", s"-$versionMajor", s"jdk$versionMajor")
val versionStrings = Seq(s"1.$versionMajor", s"-$versionMajor", s"jdk$versionMajor", s"$versionMajor.")
val fromEnv = sys.env.get(jdkVersion.toString).orElse(sys.env.get(s"${jdkVersion}_0"))
val fromEnv64 = sys.env.get(s"${jdkVersion}_x64").orElse(sys.env.get(s"${jdkVersion}_0_x64")) // teamcity style
val priorityPaths = Seq(currentJava(versionMajor), fromEnv.orElse(fromEnv64).map(new File(_))).flatten
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,20 @@ import org.jetbrains.plugins.scala.annotator.{AnnotatorHolderMock, Message, Scal
import org.jetbrains.plugins.scala.base.{FailableTest, ScalaSdkOwner}
import org.jetbrains.plugins.scala.extensions.PsiElementExt
import org.jetbrains.plugins.scala.lang.psi.api.ScalaFile
import org.jetbrains.plugins.scala.lang.psi.api.base.types.ScTypeElement
import org.jetbrains.plugins.scala.lang.psi.api.expr.ScExpression
import org.jetbrains.plugins.scala.lang.psi.types.TypePresentationContext
import org.jetbrains.plugins.scala.lang.psi.impl.ScalaPsiElementFactory
import org.jetbrains.plugins.scala.lang.psi.types.{ScType, TypePresentationContext}
import org.jetbrains.plugins.scala.lang.psi.types.api.TypePresentation
import org.jetbrains.plugins.scala.lang.psi.types.result._
import org.jetbrains.plugins.scala.project.{ProjectContext, ScalaFeatures}
import org.jetbrains.plugins.scala.util.TestUtils
import org.jetbrains.plugins.scala.util.TestUtils.ExpectedResultFromLastComment
import org.jetbrains.plugins.scala.util.assertions.PsiAssertions.assertNoParserErrors
import org.junit.Assert._

case class WrappingContext(prefix: String)

trait TypeInferenceDoTest extends TestCase with FailableTest with ScalaSdkOwner {
import Message._

Expand All @@ -32,24 +37,31 @@ trait TypeInferenceDoTest extends TestCase with FailableTest with ScalaSdkOwner

def configureFromFileText(fileName: String, fileText: Option[String]): ScalaFile

final protected def doTest(fileText: String): Unit = {
doTest(fileText, true)
final protected def doTest(fileText: String, expectedType: String)(implicit ctx: WrappingContext): Unit = {
doTest(fileText, expectedType: String, true)
}

final protected def doTest(
fileText: String,
expectedType: String,
failIfNoAnnotatorErrorsInFileIfTestIsSupposedToFail: Boolean
): Unit = {
doTest(Some(fileText), failIfNoAnnotatorErrorsInFileIfTestIsSupposedToFail = failIfNoAnnotatorErrorsInFileIfTestIsSupposedToFail)
)(implicit ctx: WrappingContext): Unit = {
doTestInternal(
fileText,
expectedType,
failIfNoAnnotatorErrorsInFileIfTestIsSupposedToFail = failIfNoAnnotatorErrorsInFileIfTestIsSupposedToFail
)
}

protected def doTest(
fileText: Option[String],
protected def doTestInternal(
fileText: String,
expectedTypeText: String,
failOnParserErrorsInFile: Boolean = true,
failIfNoAnnotatorErrorsInFileIfTestIsSupposedToFail: Boolean = true,
fileName: String = "dummy.scala"
): Unit = {
val scalaFile: ScalaFile = configureFromFileText(fileName, fileText)
)(implicit ctx: WrappingContext): Unit = {
val fullFileText = ctx.prefix + "\n" + fileText
val scalaFile: ScalaFile = configureFromFileText(fileName, Some(fullFileText))
if (failOnParserErrorsInFile) {
assertNoParserErrors(scalaFile)
}
Expand All @@ -64,35 +76,32 @@ trait TypeInferenceDoTest extends TestCase with FailableTest with ScalaSdkOwner
)
}

val expr: ScExpression = findSelectedExpression(scalaFile)
val expr: ScExpression = findLastExpression(scalaFile)
implicit val tpc: TypePresentationContext = TypePresentationContext.emptyContext
val typez = expr.`type`() match {
val exprType = expr.`type`() match {
case Right(t) if t.isUnit => expr.getTypeIgnoreBaseType
case x => x
}
typez match {
case Right(ttypez) =>
val res = ttypez.presentableText
val ExpectedResultFromLastComment(_, lastLineCommentText) = TestUtils.extractExpectedResultFromLastComment(scalaFile)
val expectedTextForCurrentVersion = extractTextForCurrentVersion(lastLineCommentText, version)

if (expectedTextForCurrentVersion.startsWith(FewVariantsMarker)) {
val results = expectedTextForCurrentVersion.substring(FewVariantsMarker.length).trim.split('\n')
if (!results.contains(res))
assertEqualsFailable(results(0), res)
}
else expectedTextForCurrentVersion match {
case ExpectedPattern(expectedExpectedTypeText) =>
val actualExpectedTypeText = expr.expectedType().map(_.presentableText).getOrElse("<none>")
assertEqualsFailable(expectedExpectedTypeText, actualExpectedTypeText)
case SimplifiedPattern(expectedText) =>
assertEqualsFailable(expectedText, TypePresentation.withoutAliases(ttypez))
case JavaTypePattern(expectedText) =>
assertEqualsFailable(expectedText, expr.`type`().map(_.toPsiType.getPresentableText()).getOrElse("<none>"))
case _ =>
assertEqualsFailable(expectedTextForCurrentVersion, res)
}
case Failure(msg) if shouldPass => fail(msg)
val expectedType =
ScalaPsiElementFactory.createTypeElementFromText(
expectedTypeText,
ScalaPsiElementFactory.createElementFromText(ctx.prefix, ScalaFeatures.default)(expr.projectContext),
null
).`type`()

val bothTypes =
for {
et <- exprType
xt <- expectedType
} yield (et, xt)

bothTypes match {
case Right((exprType, expectedType)) =>
assertEquals(expectedType.canonicalText, exprType.canonicalText)
//assertTrue(expectedType.typeSystem.equiv(expectedType, exprType))

case Left(failure) =>
fail(failure.toString())
case _ =>
}
}
Expand All @@ -115,6 +124,16 @@ trait TypeInferenceDoTest extends TestCase with FailableTest with ScalaSdkOwner
expr
}

protected def findLastExpression(scalaFile: ScalaFile): ScExpression = {
scalaFile.getChildren.lastOption match {
case Some(scExpr: ScExpression) => scExpr
case Some(other) =>
fail("Invalid last child (is not an ScExpression): " + other.getText).asInstanceOf[Nothing]
case None =>
fail("=== Not specified expression in the content ===\n" + scalaFile.getText).asInstanceOf[Nothing]
}
}

private val VersionPrefixRegex = """^\[Scala_([\w\d_]*)\](.*)""".r

// formats:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ abstract class TypeInferenceTestBase extends ScalaLightCodeInsightFixtureTestCas

override protected def sharedProjectToken = SharedTestProjectToken(this.getClass)

protected def doInjectorTest(injector: SyntheticMembersInjector): Unit = {
val extensionArea = ApplicationManager.getApplication.getExtensionArea
val extensionPoint = extensionArea.getExtensionPoint(SyntheticMembersInjector.EP_NAME)
extensionPoint.registerExtension(injector, getTestRootDisposable)
doTest()
}
// protected def doInjectorTest(injector: SyntheticMembersInjector): Unit = {
// val extensionArea = ApplicationManager.getApplication.getExtensionArea
// val extensionPoint = extensionArea.getExtensionPoint(SyntheticMembersInjector.EP_NAME)
// extensionPoint.registerExtension(injector, getTestRootDisposable)
// doTest()
// }

override def configureFromFileText(fileName: String, fileText: Option[String]): ScalaFile = {
val text = fileText.getOrElse {
Expand All @@ -42,8 +42,8 @@ abstract class TypeInferenceTestBase extends ScalaLightCodeInsightFixtureTestCas
protected def addFileToProject(fileName: String, text: String): PsiFile =
PsiFileTestUtil.addFileToProject(fileName, text, getProject)

protected def doTest(): Unit = {
val fileName = getTestName(false) + ".scala"
doTest(None, fileName = fileName)
}
// protected def doTest(): Unit = {
// val fileName = getTestName(false) + ".scala"
// doTest(None, fileName = fileName)
// }
}

0 comments on commit 235b48b

Please sign in to comment.