From fc75da4d26241f7acb17339eabc87c9842ce7a72 Mon Sep 17 00:00:00 2001 From: Jamie Date: Thu, 13 Feb 2020 10:57:56 -0800 Subject: [PATCH 1/2] Add test for scalac dependencies --- .../dependency_analyzer/src/test/BUILD | 18 +++ .../ScalacDependencyTest.scala | 105 ++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 third_party/dependency_analyzer/src/test/io/bazel/rulesscala/dependencyanalyzer/ScalacDependencyTest.scala diff --git a/third_party/dependency_analyzer/src/test/BUILD b/third_party/dependency_analyzer/src/test/BUILD index 3e09162a0..f002cb9ff 100644 --- a/third_party/dependency_analyzer/src/test/BUILD +++ b/third_party/dependency_analyzer/src/test/BUILD @@ -38,6 +38,24 @@ scala_test( ], ) +scala_test( + name = "scalac_dependency_test", + size = "small", + srcs = [ + "io/bazel/rulesscala/dependencyanalyzer/ScalacDependencyTest.scala", + ], + jvm_flags = common_jvm_flags, + unused_dependency_checker_mode = "off", + deps = [ + "//external:io_bazel_rules_scala/dependency/scala/scala_compiler", + "//external:io_bazel_rules_scala/dependency/scala/scala_library", + "//external:io_bazel_rules_scala/dependency/scala/scala_reflect", + "//third_party/dependency_analyzer/src/main:dependency_analyzer", + "//third_party/utils/src/test:test_util", + "@scalac_rules_commons_io//jar", + ], +) + scala_test( name = "strict_deps_test", size = "small", diff --git a/third_party/dependency_analyzer/src/test/io/bazel/rulesscala/dependencyanalyzer/ScalacDependencyTest.scala b/third_party/dependency_analyzer/src/test/io/bazel/rulesscala/dependencyanalyzer/ScalacDependencyTest.scala new file mode 100644 index 000000000..0dd576f0b --- /dev/null +++ b/third_party/dependency_analyzer/src/test/io/bazel/rulesscala/dependencyanalyzer/ScalacDependencyTest.scala @@ -0,0 +1,105 @@ +package third_party.dependency_analyzer.src.test.io.bazel.rulesscala.dependencyanalyzer + +import java.nio.file.Files +import java.nio.file.Path +import java.util.UUID +import org.apache.commons.io.FileUtils +import org.scalatest._ +import third_party.utils.src.test.io.bazel.rulesscala.utils.JavaCompileUtil +import third_party.utils.src.test.io.bazel.rulesscala.utils.TestUtil + +/** + * Test that the scalac compiler behaves how we expect it to around + * dependencies. That is, for given scenarios, we want to make sure + * that scalac requires the given set of dependencies; no more and + * no less. + */ +class ScalacDependencyTest extends FunSuite { + private def withSandbox(action: Sandbox => Unit): Unit = { + val tmpDir = Files.createTempDirectory("dependency_analyzer_test_temp") + val file = tmpDir.toFile + try { + action(new Sandbox(tmpDir)) + } finally { + FileUtils.deleteDirectory(file) + } + } + + private class Sandbox(tmpDir: Path) { + def compile( + code: String + ): Unit = { + val errors = + TestUtil.runCompiler( + code = code, + extraClasspath = List(tmpDir.toString), + outputPathOpt = Some(tmpDir) + ) + assert(errors.isEmpty) + } + + def compileJava( + className: String, + code: String + ): Unit = { + JavaCompileUtil.compile( + tmpDir = tmpDir.toString, + className = className, + code = code + ) + } + + def checkExactDepsNeeded( + code: String, + deps: List[String] + ): Unit = { + def doesCompileSucceed(usedDeps: List[String]): Boolean = { + val subdir = tmpDir.resolve(UUID.randomUUID().toString) + Files.createDirectory(subdir) + usedDeps.foreach { dep => + val name = s"$dep.class" + Files.copy(tmpDir.resolve(name), subdir.resolve(name)) + } + val errors = + TestUtil.runCompiler( + code = code, + extraClasspath = List(subdir.toString) + ) + errors.isEmpty + } + + assert(doesCompileSucceed(deps), s"Failed to compile with all deps") + + deps.foreach { toSkip => + val remaining = deps.filter(_ != toSkip) + // sanity check we removed exactly one item + assert(remaining.size + 1 == deps.size) + assert( + !doesCompileSucceed(remaining), + s"Compile succeeded even though $toSkip was missing") + } + } + } + + test("static annotation of superclass not needed") { + withSandbox { sandbox => + sandbox.compile("class A extends scala.annotation.StaticAnnotation") + sandbox.compile("@A class B") + sandbox.checkExactDepsNeeded( + code = "class C extends B", + deps = List("B") + ) + } + } + + test("superclass of superclass needed") { + withSandbox { sandbox => + sandbox.compile("class A") + sandbox.compile("class B extends A") + sandbox.checkExactDepsNeeded( + code = "class C extends B", + deps = List("A", "B") + ) + } + } +} From 7e8c020364af49f0c714daaa6c77a70e12b16704 Mon Sep 17 00:00:00 2001 From: Jamie Date: Mon, 17 Feb 2020 16:46:18 -0800 Subject: [PATCH 2/2] comment --- .../rulesscala/dependencyanalyzer/ScalacDependencyTest.scala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/third_party/dependency_analyzer/src/test/io/bazel/rulesscala/dependencyanalyzer/ScalacDependencyTest.scala b/third_party/dependency_analyzer/src/test/io/bazel/rulesscala/dependencyanalyzer/ScalacDependencyTest.scala index 0dd576f0b..6126d9c2e 100644 --- a/third_party/dependency_analyzer/src/test/io/bazel/rulesscala/dependencyanalyzer/ScalacDependencyTest.scala +++ b/third_party/dependency_analyzer/src/test/io/bazel/rulesscala/dependencyanalyzer/ScalacDependencyTest.scala @@ -13,6 +13,10 @@ import third_party.utils.src.test.io.bazel.rulesscala.utils.TestUtil * dependencies. That is, for given scenarios, we want to make sure * that scalac requires the given set of dependencies; no more and * no less. + * + * To clarify: these tests do not reflect the end result of strict/unused + * deps as we are considering alternatives of how to mitigate scalac's + * limitations. */ class ScalacDependencyTest extends FunSuite { private def withSandbox(action: Sandbox => Unit): Unit = {