refactor the testbench mocks so they are more composeable (#148) * refactor the testbench mocks so they are more composeable. * Add sources and output jar normalization tests
diff --git a/kotlin/internal/repositories/BUILD.com_github_jetbrains_kotlin b/kotlin/internal/repositories/BUILD.com_github_jetbrains_kotlin index 4c3dc5a..91f2964 100644 --- a/kotlin/internal/repositories/BUILD.com_github_jetbrains_kotlin +++ b/kotlin/internal/repositories/BUILD.com_github_jetbrains_kotlin
@@ -12,7 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. package(default_visibility = ["//visibility:public"]) -load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_import", "kt_js_import") + +load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_js_import", "kt_jvm_import") # Kotlin home filegroup containing everything that is needed. filegroup(
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/BUILD b/src/test/kotlin/io/bazel/kotlin/builder/BUILD index ad1523f..0ce32ad 100644 --- a/src/test/kotlin/io/bazel/kotlin/builder/BUILD +++ b/src/test/kotlin/io/bazel/kotlin/builder/BUILD
@@ -21,6 +21,7 @@ "//third_party/jvm/com/google/truth", "//third_party/jvm/junit", "@io_bazel_rules_kotlin_com_google_guava_guava//jar", + "//third_party/jvm/com/google/code/findbugs:jsr305", ] java_library( @@ -28,9 +29,10 @@ testonly = 1, srcs = [ "Deps.java", - "KotlinBuilderJsTestTask.java", - "KotlinBuilderJvmTestTask.java", - "KotlinBuilderResource.java", + "DirectoryType.java", + "KotlinAbstractTestBuilder.java", + "KotlinJsTestBuilder.java", + "KotlinJvmTestBuilder.java", ], data = [ "//src/main/kotlin:compiler_lib",
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/Deps.java b/src/test/kotlin/io/bazel/kotlin/builder/Deps.java index 8a94799..1793879 100644 --- a/src/test/kotlin/io/bazel/kotlin/builder/Deps.java +++ b/src/test/kotlin/io/bazel/kotlin/builder/Deps.java
@@ -16,9 +16,12 @@ package io.bazel.kotlin.builder; import com.google.auto.value.AutoValue; -import com.google.common.collect.ImmutableSet; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; import io.bazel.kotlin.builder.utils.BazelRunFiles; +import javax.annotation.Nullable; +import java.util.List; import java.util.Optional; import java.util.Set; import java.util.stream.Stream; @@ -31,22 +34,33 @@ public abstract String moduleName(); - public abstract Set<String> runtimeDeps(); + public abstract List<String> runtimeDeps(); - public abstract Set<String> compileJars(); + public abstract List<String> compileJars(); + + @Nullable + public abstract String sourceJar(); + + @Nullable + public abstract String jdeps(); public static Builder builder() { - return new AutoValue_Deps_Dep.Builder().runtimeDeps(ImmutableSet.of()); + return new AutoValue_Deps_Dep.Builder().runtimeDeps(ImmutableList.of()); + } + + public final String singleCompileJar() { + Preconditions.checkState(compileJars().size() == 1); + return compileJars().get(0); } @SuppressWarnings("UnusedReturnValue") @AutoValue.Builder public abstract static class Builder { - public abstract Builder compileJars(Set<String> compileJars); + public abstract Builder compileJars(List<String> compileJars); public abstract Builder label(String label); - public abstract Builder runtimeDeps(Set<String> runtimeDeps); + public abstract Builder runtimeDeps(List<String> runtimeDeps); public abstract Builder moduleName(String moduleName); @@ -56,6 +70,10 @@ abstract Dep autoBuild(); + public abstract Builder sourceJar(String sourceJar); + + public abstract Builder jdeps(String jdeps); + public Dep build() { if (!moduleName().isPresent()) { moduleName(label()); @@ -73,7 +91,8 @@ public static Dep importJar(String label, String compileJar) { return Dep.builder() .label(label) - .compileJars(ImmutableSet.of(BazelRunFiles.resolveVerified(compileJar).getAbsolutePath())) + .compileJars( + ImmutableList.of(BazelRunFiles.resolveVerified(compileJar).getAbsolutePath())) .build(); } }
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/DirectoryType.java b/src/test/kotlin/io/bazel/kotlin/builder/DirectoryType.java new file mode 100644 index 0000000..10e19ce --- /dev/null +++ b/src/test/kotlin/io/bazel/kotlin/builder/DirectoryType.java
@@ -0,0 +1,38 @@ +package io.bazel.kotlin.builder; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.EnumSet; + +public enum DirectoryType { + SOURCES("sources", Paths.get("sources")), + CLASSES("compiled classes", Paths.get("classes")), + GENERATED_CLASSES("generated classes", Paths.get("generated_classes")), + TEMP("temp directory", Paths.get("temp")), + SOURCE_GEN("generated sources directory", Paths.get("generated_sources")); + + final String name; + final Path relativePath; + + DirectoryType(String name, Path relativePath) { + this.name = name; + this.relativePath = relativePath; + } + + Path resolve(Path root) { + return root.resolve(relativePath); + } + + static void createAll(Path root, EnumSet<DirectoryType> types) { + for (DirectoryType instanceType : types) { + try { + Files.createDirectory(instanceType.resolve(root)); + } catch (IOException e) { + throw new UncheckedIOException(instanceType.name, e); + } + } + } +}
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderResource.java b/src/test/kotlin/io/bazel/kotlin/builder/KotlinAbstractTestBuilder.java similarity index 73% rename from src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderResource.java rename to src/test/kotlin/io/bazel/kotlin/builder/KotlinAbstractTestBuilder.java index 272d377..bcf18ab 100644 --- a/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderResource.java +++ b/src/test/kotlin/io/bazel/kotlin/builder/KotlinAbstractTestBuilder.java
@@ -17,17 +17,16 @@ import io.bazel.kotlin.builder.toolchain.CompilationStatusException; import io.bazel.kotlin.builder.utils.CompilationTaskContext; -import io.bazel.kotlin.model.CompilationTaskInfo; -import io.bazel.kotlin.model.KotlinToolchainInfo; -import io.bazel.kotlin.model.Platform; -import io.bazel.kotlin.model.RuleKind; -import org.junit.rules.ExternalResource; +import io.bazel.kotlin.model.*; import java.io.*; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.*; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiFunction; import java.util.function.Consumer; @@ -37,42 +36,17 @@ import static com.google.common.truth.Truth.assertWithMessage; import static java.nio.charset.StandardCharsets.UTF_8; -public abstract class KotlinBuilderResource<T> extends ExternalResource { - public enum DirectoryType { - INSTANCE_ROOT("test root", null), - EXTERNAL("bazel external directory", null), - /** The rest of the paths are instance relative. */ - SOURCES("sources", Paths.get("sources")), - CLASSES("compiled classes", Paths.get("classes")), - GENERATED_CLASSES("generated classes", Paths.get("generated_classes")), - TEMP("temp directory", Paths.get("temp")), - SOURCE_GEN("generated sources directory", Paths.get("generated_sources")); - - private static final EnumSet<DirectoryType> INSTANCE_TYPES = - EnumSet.of(SOURCES, CLASSES, SOURCE_GEN, GENERATED_CLASSES, TEMP); - - final String name; - private final Path relativePath; - - DirectoryType(String name, Path relativePath) { - this.name = name; - this.relativePath = relativePath; - } - } - - private static final Path - BAZEL_TEST_DIR = Paths.get(Objects.requireNonNull(System.getenv("TEST_TMPDIR"))), - EXTERNAL_PATH = Paths.get("external"); +abstract class KotlinAbstractTestBuilder<T> { + private static final Path BAZEL_TEST_DIR = + Paths.get(Objects.requireNonNull(System.getenv("TEST_TMPDIR"))); private static final AtomicInteger counter = new AtomicInteger(0); - + private final CompilationTaskInfo.Builder infoBuilder = CompilationTaskInfo.newBuilder(); private Path instanceRoot = null; private String label = null; private List<String> outLines = null; - KotlinBuilderResource() {} - - abstract CompilationTaskInfo.Builder infoBuilder(); + abstract void setupForNext(CompilationTaskInfo.Builder infoBuilder); abstract T buildTask(); @@ -89,11 +63,10 @@ return outLines; } - @Override - protected void before() throws Throwable { + final void resetForNext() { outLines = null; label = "a_test_" + counter.incrementAndGet(); - infoBuilder() + infoBuilder .setLabel("//some/bogus:" + label()) .setModuleName("some_bogus_module") .setPlatform(Platform.JVM) @@ -111,36 +84,16 @@ } catch (IOException e) { throw new UncheckedIOException(e); } - - for (DirectoryType instanceType : DirectoryType.INSTANCE_TYPES) { - try { - Files.createDirectory(instanceRoot.resolve(instanceType.relativePath)); - } catch (IOException e) { - throw new RuntimeException("could not create instance directory: " + instanceType.name, e); - } - } + setupForNext(infoBuilder); } final Path directory(DirectoryType type) { - switch (type) { - case INSTANCE_ROOT: - return instanceRoot; - case EXTERNAL: - return KotlinBuilderResource.EXTERNAL_PATH; - case SOURCES: - case CLASSES: - case GENERATED_CLASSES: - case TEMP: - case SOURCE_GEN: - return instanceRoot.resolve(type.relativePath); - default: - throw new IllegalStateException(type.toString()); - } + return type.resolve(instanceRoot); } @SuppressWarnings("unused") public final void setDebugTags(String... tags) { - infoBuilder().addAllDebug(Arrays.asList(tags)); + infoBuilder.addAllDebug(Arrays.asList(tags)); } final Path writeSourceFile(String filename, String[] lines) { @@ -174,9 +127,8 @@ } final <R> R runCompileTask(BiFunction<CompilationTaskContext, T, R> operation) { - CompilationTaskInfo info = infoBuilder().build(); T task = buildTask(); - return runCompileTask(info, task, (ctx, t) -> operation.apply(ctx, task)); + return runCompileTask(infoBuilder.build(), task, (ctx, t) -> operation.apply(ctx, task)); } /** @@ -238,7 +190,7 @@ } public final String toPlatform(String path) { - return KotlinBuilderResource.toPlatformPath(path).toString(); + return KotlinAbstractTestBuilder.toPlatformPath(path).toString(); } @SuppressWarnings("unused")
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderJvmTestTask.java b/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderJvmTestTask.java deleted file mode 100644 index 824a742..0000000 --- a/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderJvmTestTask.java +++ /dev/null
@@ -1,148 +0,0 @@ -/* - * Copyright 2018 The Bazel Authors. All rights reserved. - * - * 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 io.bazel.kotlin.builder; - -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableSet; -import io.bazel.kotlin.builder.toolchain.KotlinToolchain; -import io.bazel.kotlin.model.CompilationTaskInfo; -import io.bazel.kotlin.model.JvmCompilationTask; - -import java.util.HashSet; -import java.util.function.Consumer; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static io.bazel.kotlin.builder.Deps.*; - -public final class KotlinBuilderJvmTestTask extends KotlinBuilderResource<JvmCompilationTask> { - @SuppressWarnings({"unused", "WeakerAccess"}) - public static Dep - KOTLIN_ANNOTATIONS = - Dep.importJar( - "kotlin-annotations", - "external/com_github_jetbrains_kotlin/lib/annotations-13.0.jar"), - KOTLIN_STDLIB = - Dep.importJar( - "kotlin-stdlib", "external/com_github_jetbrains_kotlin/lib/kotlin-stdlib.jar"), - KOTLIN_STDLIB_JDK7 = - Dep.importJar( - "kotlin-stdlib-jdk7", - "external/com_github_jetbrains_kotlin/lib/kotlin-stdlib-jdk7.jar"), - KOTLIN_STDLIB_JDK8 = - Dep.importJar( - "kotlin-stdlib-jdk8", - "external/com_github_jetbrains_kotlin/lib/kotlin-stdlib-jdk8.jar"); - - private static final JvmCompilationTask.Builder taskBuilder = JvmCompilationTask.newBuilder(); - private static final KotlinBuilderComponent component = - DaggerKotlinBuilderComponent.builder().toolchain(KotlinToolchain.createToolchain()).build(); - - @Override - CompilationTaskInfo.Builder infoBuilder() { - return taskBuilder.getInfoBuilder(); - } - - @Override - JvmCompilationTask buildTask() { - return taskBuilder.build(); - } - - @Override - protected final void before() throws Throwable { - taskBuilder.clear(); - super.before(); - - taskBuilder - .getDirectoriesBuilder() - .setClasses(directory(DirectoryType.CLASSES).toAbsolutePath().toString()) - .setGeneratedSources(directory(DirectoryType.SOURCE_GEN).toAbsolutePath().toString()) - .setTemp(directory(DirectoryType.TEMP).toAbsolutePath().toString()) - .setGeneratedClasses( - directory(DirectoryType.GENERATED_CLASSES).toAbsolutePath().toString()); - taskBuilder - .getOutputsBuilder() - .setJar(instanceRoot().resolve("jar_file.jar").toAbsolutePath().toString()) - .setJdeps(instanceRoot().resolve("jdeps_file.jdeps").toAbsolutePath().toString()) - .setSrcjar(instanceRoot().resolve("jar_file-sources.jar").toAbsolutePath().toString()); - } - - private void resetForNext() { - try { - before(); - } catch (Throwable throwable) { - throw new RuntimeException(throwable); - } - } - - public void addSource(String filename, String... lines) { - String pathAsString = super.writeSourceFile(filename, lines).toString(); - if (pathAsString.endsWith(".kt")) { - taskBuilder.getInputsBuilder().addKotlinSources(pathAsString); - } else if (pathAsString.endsWith(".java")) { - taskBuilder.getInputsBuilder().addJavaSources(pathAsString); - } else { - throw new RuntimeException("unhandled file type: " + pathAsString); - } - } - - public void addAnnotationProcessors(AnnotationProcessor... annotationProcessors) { - Preconditions.checkState( - taskBuilder.getInputs().getProcessorsList().isEmpty(), "processors already set"); - HashSet<String> processorClasses = new HashSet<>(); - taskBuilder - .getInputsBuilder() - .addAllProcessorpaths( - Stream.of(annotationProcessors) - .peek(it -> processorClasses.add(it.processClass())) - .flatMap(it -> it.processorPath().stream()) - .distinct() - .collect(Collectors.toList())) - .addAllProcessors(processorClasses); - } - - public void addDirectDependencies(Dep... dependencies) { - Dep.classpathOf(dependencies) - .forEach((dependency) -> taskBuilder.getInputsBuilder().addClasspath(dependency)); - } - - private Dep currentDep() { - return Dep.builder() - .label(label()) - .compileJars(ImmutableSet.of(taskBuilder.getOutputs().getJar())) - .runtimeDeps(ImmutableSet.copyOf(taskBuilder.getInputs().getClasspathList())) - .build(); - } - - @SafeVarargs - public final Dep runCompileTask(Consumer<KotlinBuilderJvmTestTask>... setup) { - Stream.of(setup).forEach(it -> it.accept(this)); - return runCompileTask( - (taskContext, task) -> { - component.jvmTaskExecutor().execute(taskContext, task); - assertFilesExist(task.getOutputs().getJar(), task.getOutputs().getJdeps()); - return currentDep(); - }); - } - - /** Run a single compile task returning a dep and resetting the context. */ - @SafeVarargs - public final Dep supplyDepTask(Consumer<KotlinBuilderJvmTestTask>... setup) { - Dep dep = runCompileTask(setup); - resetForNext(); - return dep; - } -}
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderJsTestTask.java b/src/test/kotlin/io/bazel/kotlin/builder/KotlinJsTestBuilder.java similarity index 72% rename from src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderJsTestTask.java rename to src/test/kotlin/io/bazel/kotlin/builder/KotlinJsTestBuilder.java index ff65016..c7a79ef 100644 --- a/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderJsTestTask.java +++ b/src/test/kotlin/io/bazel/kotlin/builder/KotlinJsTestBuilder.java
@@ -19,21 +19,19 @@ import io.bazel.kotlin.model.CompilationTaskInfo; import io.bazel.kotlin.model.JsCompilationTask; -import java.nio.file.Path; import java.util.Arrays; +import java.util.EnumSet; import java.util.List; +import java.util.function.Consumer; -public final class KotlinBuilderJsTestTask extends KotlinBuilderResource<JsCompilationTask> { +public final class KotlinJsTestBuilder extends KotlinAbstractTestBuilder<JsCompilationTask> { private static final List<String> PASSTHROUGH_FLAGS = Arrays.asList("-source-map", "-meta-info", "-module-kind", "commonjs", "-target", "v5"); private static final JsCompilationTask.Builder taskBuilder = JsCompilationTask.newBuilder(); private static final KotlinBuilderComponent component = DaggerKotlinBuilderComponent.builder().toolchain(KotlinToolchain.createToolchain()).build(); - - @Override - CompilationTaskInfo.Builder infoBuilder() { - return taskBuilder.getInfoBuilder(); - } + private static final EnumSet<DirectoryType> ALL_DIRECTORY_TYPES = + EnumSet.of(DirectoryType.SOURCES); @Override JsCompilationTask buildTask() { @@ -41,10 +39,9 @@ } @Override - protected final void before() throws Throwable { - taskBuilder.clear(); - super.before(); - + void setupForNext(CompilationTaskInfo.Builder infoBuilder) { + taskBuilder.clear().setInfo(infoBuilder); + DirectoryType.createAll(instanceRoot(), ALL_DIRECTORY_TYPES); taskBuilder.addAllPassThroughFlags(PASSTHROUGH_FLAGS); taskBuilder .getOutputsBuilder() @@ -53,12 +50,17 @@ .setJs(instanceRoot().resolve(label() + ".js").toAbsolutePath().toString()); } - public void addSource(String filename, String... lines) { - Path sourcePath = super.writeSourceFile(filename, lines); - taskBuilder.getInputsBuilder().addKotlinSources(sourcePath.toString()); + public final class TaskBuilder { + public void addSource(String filename, String... lines) { + taskBuilder.getInputsBuilder().addKotlinSources(writeSourceFile(filename, lines).toString()); + } } - public void runCompilationTask() { + private final TaskBuilder taskBuilderInstance = new TaskBuilder(); + + public void runCompilationTask(Consumer<TaskBuilder> setup) { + resetForNext(); + setup.accept(taskBuilderInstance); runCompileTask( (taskContext, task) -> { component.jsTaskExecutor().execute(taskContext, task);
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/KotlinJvmTestBuilder.java b/src/test/kotlin/io/bazel/kotlin/builder/KotlinJvmTestBuilder.java new file mode 100644 index 0000000..56c38a7 --- /dev/null +++ b/src/test/kotlin/io/bazel/kotlin/builder/KotlinJvmTestBuilder.java
@@ -0,0 +1,146 @@ +/* + * Copyright 2018 The Bazel Authors. All rights reserved. + * + * 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 io.bazel.kotlin.builder; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import io.bazel.kotlin.builder.Deps.AnnotationProcessor; +import io.bazel.kotlin.builder.Deps.Dep; +import io.bazel.kotlin.builder.toolchain.KotlinToolchain; +import io.bazel.kotlin.model.CompilationTaskInfo; +import io.bazel.kotlin.model.JvmCompilationTask; + +import java.util.EnumSet; +import java.util.HashSet; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public final class KotlinJvmTestBuilder extends KotlinAbstractTestBuilder<JvmCompilationTask> { + @SuppressWarnings({"unused", "WeakerAccess"}) + public static Dep + KOTLIN_ANNOTATIONS = + Dep.importJar( + "kotlin-annotations", + "external/com_github_jetbrains_kotlin/lib/annotations-13.0.jar"), + KOTLIN_STDLIB = + Dep.importJar( + "kotlin-stdlib", "external/com_github_jetbrains_kotlin/lib/kotlin-stdlib.jar"), + KOTLIN_STDLIB_JDK7 = + Dep.importJar( + "kotlin-stdlib-jdk7", + "external/com_github_jetbrains_kotlin/lib/kotlin-stdlib-jdk7.jar"), + KOTLIN_STDLIB_JDK8 = + Dep.importJar( + "kotlin-stdlib-jdk8", + "external/com_github_jetbrains_kotlin/lib/kotlin-stdlib-jdk8.jar"); + + private static final JvmCompilationTask.Builder taskBuilder = JvmCompilationTask.newBuilder(); + private static final KotlinBuilderComponent component = + DaggerKotlinBuilderComponent.builder().toolchain(KotlinToolchain.createToolchain()).build(); + + private static final EnumSet<DirectoryType> ALL_DIRECTORY_TYPES = + EnumSet.of( + DirectoryType.SOURCES, + DirectoryType.CLASSES, + DirectoryType.SOURCE_GEN, + DirectoryType.GENERATED_CLASSES, + DirectoryType.TEMP); + + @Override + void setupForNext(CompilationTaskInfo.Builder taskInfo) { + taskBuilder.clear().setInfo(taskInfo); + + DirectoryType.createAll(instanceRoot(), ALL_DIRECTORY_TYPES); + + taskBuilder + .getDirectoriesBuilder() + .setClasses(directory(DirectoryType.CLASSES).toAbsolutePath().toString()) + .setGeneratedSources(directory(DirectoryType.SOURCE_GEN).toAbsolutePath().toString()) + .setTemp(directory(DirectoryType.TEMP).toAbsolutePath().toString()) + .setGeneratedClasses( + directory(DirectoryType.GENERATED_CLASSES).toAbsolutePath().toString()); + + taskBuilder + .getOutputsBuilder() + .setJar(instanceRoot().resolve("jar_file.jar").toAbsolutePath().toString()) + .setJdeps(instanceRoot().resolve("jdeps_file.jdeps").toAbsolutePath().toString()) + .setSrcjar(instanceRoot().resolve("jar_file-sources.jar").toAbsolutePath().toString()); + } + + @Override + JvmCompilationTask buildTask() { + return taskBuilder.build(); + } + + public class TaskBuilder { + TaskBuilder() {} + + public void setLabel(String label) { + taskBuilder.getInfoBuilder().setLabel(label); + } + + public void addSource(String filename, String... lines) { + String pathAsString = writeSourceFile(filename, lines).toString(); + if (pathAsString.endsWith(".kt")) { + taskBuilder.getInputsBuilder().addKotlinSources(pathAsString); + } else if (pathAsString.endsWith(".java")) { + taskBuilder.getInputsBuilder().addJavaSources(pathAsString); + } else { + throw new RuntimeException("unhandled file type: " + pathAsString); + } + } + + public void addAnnotationProcessors(AnnotationProcessor... annotationProcessors) { + Preconditions.checkState( + taskBuilder.getInputs().getProcessorsList().isEmpty(), "processors already set"); + HashSet<String> processorClasses = new HashSet<>(); + taskBuilder + .getInputsBuilder() + .addAllProcessorpaths( + Stream.of(annotationProcessors) + .peek(it -> processorClasses.add(it.processClass())) + .flatMap(it -> it.processorPath().stream()) + .distinct() + .collect(Collectors.toList())) + .addAllProcessors(processorClasses); + } + + public void addDirectDependencies(Dep... dependencies) { + Dep.classpathOf(dependencies) + .forEach((dependency) -> taskBuilder.getInputsBuilder().addClasspath(dependency)); + } + } + + private TaskBuilder taskBuilderInstance = new TaskBuilder(); + + @SafeVarargs + public final Dep runCompileTask(Consumer<TaskBuilder>... setup) { + resetForNext(); + Stream.of(setup).forEach(it -> it.accept(taskBuilderInstance)); + return runCompileTask( + (taskContext, task) -> { + component.jvmTaskExecutor().execute(taskContext, task); + assertFilesExist(task.getOutputs().getJar(), task.getOutputs().getJdeps()); + return Dep.builder() + .label(taskBuilder.getInfo().getLabel()) + .compileJars(ImmutableList.of(taskBuilder.getOutputs().getJar())) + .runtimeDeps(ImmutableList.copyOf(taskBuilder.getInputs().getClasspathList())) + .sourceJar(taskBuilder.getOutputs().getSrcjar()) + .build(); + }); + } +}
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/tasks/js/KotlinBuilderJsTest.java b/src/test/kotlin/io/bazel/kotlin/builder/tasks/js/KotlinBuilderJsTest.java index 41c2ef6..c7e1109 100644 --- a/src/test/kotlin/io/bazel/kotlin/builder/tasks/js/KotlinBuilderJsTest.java +++ b/src/test/kotlin/io/bazel/kotlin/builder/tasks/js/KotlinBuilderJsTest.java
@@ -1,6 +1,6 @@ package io.bazel.kotlin.builder.tasks.js; -import io.bazel.kotlin.builder.KotlinBuilderJsTestTask; +import io.bazel.kotlin.builder.KotlinJsTestBuilder; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -10,19 +10,20 @@ @RunWith(JUnit4.class) public class KotlinBuilderJsTest { - @Rule public KotlinBuilderJsTestTask ctx = new KotlinBuilderJsTestTask(); + private static final KotlinJsTestBuilder builder = new KotlinJsTestBuilder(); @Test public void testSimpleJsCompile() { - ctx.addSource("AClass.kt", "package something", "class AClass{}"); - ctx.runCompilationTask(); + builder.runCompilationTask( + it -> it.addSource("AClass.kt", "package something", "class AClass{}")); } @Test public void testJsErrorRendering() { - ctx.addSource("AClass.kt", "package something", "class AClass{"); - ctx.runFailingCompileTaskAndValidateOutput( - ctx::runCompilationTask, - lines -> assertThat(lines.get(0)).startsWith(ctx.toPlatform("sources/AClass.kt"))); + builder.runFailingCompileTaskAndValidateOutput( + () -> + builder.runCompilationTask( + it -> it.addSource("AClass.kt", "package something", "class AClass{")), + lines -> assertThat(lines.get(0)).startsWith(builder.toPlatform("sources/AClass.kt"))); } }
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinBuilderJvmBasicTest.java b/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinBuilderJvmBasicTest.java index ffe49ce..75ebc75 100644 --- a/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinBuilderJvmBasicTest.java +++ b/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinBuilderJvmBasicTest.java
@@ -15,67 +15,81 @@ */ package io.bazel.kotlin.builder.tasks.jvm; -import io.bazel.kotlin.builder.KotlinBuilderJvmTestTask; -import io.bazel.kotlin.builder.KotlinBuilderResource.DirectoryType; +import io.bazel.kotlin.builder.Deps; +import io.bazel.kotlin.builder.DirectoryType; +import io.bazel.kotlin.builder.KotlinJvmTestBuilder; import org.junit.Ignore; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.function.Consumer; + import static com.google.common.truth.Truth.assertThat; @RunWith(JUnit4.class) public class KotlinBuilderJvmBasicTest { - @Rule public KotlinBuilderJvmTestTask ctx = new KotlinBuilderJvmTestTask(); + private static final KotlinJvmTestBuilder ctx = new KotlinJvmTestBuilder(); @Test public void testSimpleMixedModeCompile() { - ctx.addSource("AClass.kt", "package something;" + "class AClass{}"); - ctx.addSource("AnotherClass.java", "package something;", "", "class AnotherClass{}"); - ctx.runCompileTask(); + ctx.runCompileTask( + c -> { + c.addSource("AClass.kt", "package something;" + "class AClass{}"); + c.addSource("AnotherClass.java", "package something;", "", "class AnotherClass{}"); + }); ctx.assertFilesExist( DirectoryType.CLASSES, "something/AClass.class", "something/AnotherClass.class"); } @Test public void testMixedBiReferences() { - ctx.addSource( - "AClass.java", - "package a;", - "", - "import b.BClass;", - "", - "public class AClass {", - " static BClass b = new BClass();", - "}"); - ctx.addSource( - "BClass.kt", - "package b", - "", - "import a.AClass", - "", - "class BClass() {", - " val a = AClass()", - "}"); - ctx.runCompileTask(); + ctx.runCompileTask( + it -> { + it.addSource( + "AClass.java", + "package a;", + "", + "import b.BClass;", + "", + "public class AClass {", + " static BClass b = new BClass();", + "}"); + it.addSource( + "BClass.kt", + "package b", + "", + "import a.AClass", + "", + "class BClass() {", + " val a = AClass()", + "}"); + }); ctx.assertFilesExist(DirectoryType.CLASSES, "a/AClass.class", "b/BClass.class"); } @Test public void testKotlinErrorRendering() { - ctx.addSource("AClass.kt", "package something;" + "class AClass{"); ctx.runFailingCompileTaskAndValidateOutput( - ctx::runCompileTask, + () -> + ctx.runCompileTask( + c -> c.addSource("AClass.kt", "package something;" + "class AClass{")), lines -> assertThat(lines.get(0)).startsWith(ctx.toPlatform("sources/AClass"))); } @Test public void testJavaErrorRendering() { - ctx.addSource("AClass.kt", "package something;" + "class AClass{}"); - ctx.addSource("AnotherClass.java", "package something;", "", "class AnotherClass{"); ctx.runFailingCompileTaskAndValidateOutput( - ctx::runCompileTask, + () -> + ctx.runCompileTask( + c -> { + c.addSource("AClass.kt", "package something;" + "class AClass{}"); + c.addSource("AnotherClass.java", "package something;", "", "class AnotherClass{"); + }), lines -> assertThat(lines.get(0)).startsWith(ctx.toPlatform("sources/AnotherClass"))); } @@ -85,4 +99,42 @@ ctx.runCompileTask( (c) -> c.addSource("AnotherClass.java", "package something;", "", "class AnotherClass{}")); } + + private static final Consumer<KotlinJvmTestBuilder.TaskBuilder> SETUP_NORMALIZATION_TEST_SOURCES = + ctx -> { + ctx.addSource("AClass.kt", "package something;\n" + "class AClass{}"); + ctx.addSource("BClass.kt", "package something;\n" + "class BClass{}"); + }; + + @Test + public void testCompiledJarIsNormalized() { + Deps.Dep previous = ctx.runCompileTask(SETUP_NORMALIZATION_TEST_SOURCES); + Deps.Dep recompiled = + ctx.runCompileTask(ctx -> ctx.setLabel(previous.label()), SETUP_NORMALIZATION_TEST_SOURCES); + assertThat(previous.label()).isEqualTo(recompiled.label()); + assertThat(hashDep(previous.singleCompileJar())) + .isEqualTo(hashDep(recompiled.singleCompileJar())); + assertThat(previous.sourceJar()).isNotEmpty(); + assertThat(hashDep(previous.sourceJar())).isEqualTo(hashDep(recompiled.sourceJar())); + } + + @Test + public void testSourceJarIsNormalized() { + Deps.Dep previous = ctx.runCompileTask(SETUP_NORMALIZATION_TEST_SOURCES); + Deps.Dep recompiled = + ctx.runCompileTask(ctx -> ctx.setLabel(previous.label()), SETUP_NORMALIZATION_TEST_SOURCES); + assertThat(previous.sourceJar()).isNotEmpty(); + assertThat(hashDep(previous.sourceJar())).isEqualTo(hashDep(recompiled.sourceJar())); + } + + private static String hashDep(String path) { + try { + //noinspection UnstableApiUsage + return com.google.common.hash.Hashing.sha256() + .hashBytes(Files.readAllBytes(Paths.get(path))) + .toString(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } }
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinBuilderJvmKaptTest.java b/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinBuilderJvmKaptTest.java index 553d560..456501f 100644 --- a/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinBuilderJvmKaptTest.java +++ b/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinBuilderJvmKaptTest.java
@@ -17,9 +17,8 @@ import io.bazel.kotlin.builder.Deps.AnnotationProcessor; import io.bazel.kotlin.builder.Deps.Dep; -import io.bazel.kotlin.builder.KotlinBuilderJvmTestTask; -import io.bazel.kotlin.builder.KotlinBuilderResource; -import org.junit.Rule; +import io.bazel.kotlin.builder.DirectoryType; +import io.bazel.kotlin.builder.KotlinJvmTestBuilder; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -27,8 +26,8 @@ import java.util.function.Consumer; import java.util.stream.Collectors; -import static io.bazel.kotlin.builder.KotlinBuilderJvmTestTask.KOTLIN_ANNOTATIONS; -import static io.bazel.kotlin.builder.KotlinBuilderJvmTestTask.KOTLIN_STDLIB; +import static io.bazel.kotlin.builder.KotlinJvmTestBuilder.KOTLIN_ANNOTATIONS; +import static io.bazel.kotlin.builder.KotlinJvmTestBuilder.KOTLIN_STDLIB; @RunWith(JUnit4.class) public class KotlinBuilderJvmKaptTest { @@ -44,9 +43,9 @@ Dep.classpathOf(AUTO_VALUE, KOTLIN_ANNOTATIONS).collect(Collectors.toSet())) .build(); - @Rule public KotlinBuilderJvmTestTask ctx = new KotlinBuilderJvmTestTask(); + private static final KotlinJvmTestBuilder ctx = new KotlinJvmTestBuilder(); - private static final Consumer<KotlinBuilderJvmTestTask> ADD_AUTO_VALUE_PLUGIN = + private static final Consumer<KotlinJvmTestBuilder.TaskBuilder> ADD_AUTO_VALUE_PLUGIN = (c) -> { c.addAnnotationProcessors(AUTO_VALUE_ANNOTATION_PROCESSOR); c.addDirectDependencies(AUTO_VALUE, KOTLIN_STDLIB); @@ -76,19 +75,18 @@ + "}")); ctx.assertFilesExist( - KotlinBuilderResource.DirectoryType.CLASSES, + DirectoryType.CLASSES, "autovalue/TestKtValue.class", "autovalue/AutoValue_TestKtValue.class"); - ctx.assertFilesExist( - KotlinBuilderResource.DirectoryType.SOURCE_GEN, "autovalue/AutoValue_TestKtValue.java"); + ctx.assertFilesExist(DirectoryType.SOURCE_GEN, "autovalue/AutoValue_TestKtValue.java"); } @Test public void testMixedKaptBiReferences() { ctx.runCompileTask( ADD_AUTO_VALUE_PLUGIN, - ctx -> { - ctx.addSource( + it -> { + it.addSource( "TestKtValue.kt", "package autovalue.a\n" + "\n" @@ -107,7 +105,7 @@ + " }\n" + "}"); - ctx.addSource( + it.addSource( "TestAutoValue.java", "package autovalue.b;\n" + "\n" @@ -132,11 +130,11 @@ + "}"); }); ctx.assertFilesExist( - KotlinBuilderResource.DirectoryType.SOURCE_GEN, + DirectoryType.SOURCE_GEN, "autovalue/a/AutoValue_TestKtValue.java", "autovalue/b/AutoValue_TestAutoValue.java"); ctx.assertFilesExist( - KotlinBuilderResource.DirectoryType.CLASSES, + DirectoryType.CLASSES, "autovalue/a/AutoValue_TestKtValue.class", "autovalue/b/AutoValue_TestAutoValue.class"); }
diff --git a/third_party/dependencies.yaml b/third_party/dependencies.yaml index c5bca82..9eaa370 100644 --- a/third_party/dependencies.yaml +++ b/third_party/dependencies.yaml
@@ -11,6 +11,10 @@ namePrefix: "io_bazel_rules_kotlin_" dependencies: + com.google.code.findbugs: + jsr305: + lang: "java" + version: "3.0.2" junit: junit: lang: "java"
diff --git a/third_party/jvm/com/google/code/findbugs/BUILD b/third_party/jvm/com/google/code/findbugs/BUILD index 8cd1a41..ab817e9 100644 --- a/third_party/jvm/com/google/code/findbugs/BUILD +++ b/third_party/jvm/com/google/code/findbugs/BUILD
@@ -5,7 +5,7 @@ "//external:jar/io_bazel_rules_kotlin_com/google/code/findbugs/jsr305" ], visibility = [ - "//third_party/jvm:__subpackages__" + "//visibility:public" ] )
diff --git a/third_party/jvm/workspace.bzl b/third_party/jvm/workspace.bzl index fc0c2a1..905cbf8 100644 --- a/third_party/jvm/workspace.bzl +++ b/third_party/jvm/workspace.bzl
@@ -69,7 +69,7 @@ {"artifact": "com.google.auto.service:auto-service:1.0-rc4", "lang": "java", "sha1": "44954d465f3b9065388bbd2fc08a3eb8fd07917c", "sha256": "e422d49c312fd2031222e7306e8108c1b4118eb9c049f1b51eca280bed87e924", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/auto/service/auto-service/1.0-rc4/auto-service-1.0-rc4.jar", "source": {"sha1": "4e0285a57f33a9139e203687a617d7c98104b73a", "sha256": "285a6d4bc111255b5c99f5393b833f8b9156c4acb4e6c3f7cdde8493e888dd27", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/auto/service/auto-service/1.0-rc4/auto-service-1.0-rc4-sources.jar"} , "name": "io_bazel_rules_kotlin_com_google_auto_service_auto_service", "actual": "@io_bazel_rules_kotlin_com_google_auto_service_auto_service//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/auto/service/auto_service"}, {"artifact": "com.google.auto.value:auto-value:1.5.3", "lang": "java", "sha1": "514df6a7c7938de35c7f68dc8b8f22df86037f38", "sha256": "238d3b7535096d782d08576d1e42f79480713ff0794f511ff2cc147363ec072d", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/auto/value/auto-value/1.5.3/auto-value-1.5.3.jar", "source": {"sha1": "1bb4def82e18be0b6a58ab089fba288d712db6cb", "sha256": "7c9adb9f49a4f07e226778951e087da85759a9ab53ac375f9d076de6dc84ca2b", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/auto/value/auto-value/1.5.3/auto-value-1.5.3-sources.jar"} , "name": "io_bazel_rules_kotlin_com_google_auto_value_auto_value", "actual": "@io_bazel_rules_kotlin_com_google_auto_value_auto_value//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/auto/value/auto_value"}, {"artifact": "com.google.auto:auto-common:0.8", "lang": "java", "sha1": "c6f7af0e57b9d69d81b05434ef9f3c5610d498c4", "sha256": "97db1709f57b91b32edacb596ef4641872f227b7d99ad90e467f0d77f5ba134a", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/auto/auto-common/0.8/auto-common-0.8.jar", "source": {"sha1": "24705cafc9997c5eb6ae3270bd6234fdf9912bad", "sha256": "1e258bc08963dc8ffdcf22efa04b9fea6886761e077fc126ebacf92d11c9abec", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/auto/auto-common/0.8/auto-common-0.8-sources.jar"} , "name": "io_bazel_rules_kotlin_com_google_auto_auto_common", "actual": "@io_bazel_rules_kotlin_com_google_auto_auto_common//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/auto/auto_common"}, - {"artifact": "com.google.code.findbugs:jsr305:1.3.9", "lang": "java", "sha1": "40719ea6961c0cb6afaeb6a921eaa1f6afd4cfdf", "sha256": "905721a0eea90a81534abb7ee6ef4ea2e5e645fa1def0a5cd88402df1b46c9ed", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/code/findbugs/jsr305/1.3.9/jsr305-1.3.9.jar", "name": "io_bazel_rules_kotlin_com_google_code_findbugs_jsr305", "actual": "@io_bazel_rules_kotlin_com_google_code_findbugs_jsr305//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/code/findbugs/jsr305"}, + {"artifact": "com.google.code.findbugs:jsr305:3.0.2", "lang": "java", "sha1": "25ea2e8b0c338a877313bd4672d3fe056ea78f0d", "sha256": "766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar", "source": {"sha1": "b19b5927c2c25b6c70f093767041e641ae0b1b35", "sha256": "1c9e85e272d0708c6a591dc74828c71603053b48cc75ae83cce56912a2aa063b", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2-sources.jar"} , "name": "io_bazel_rules_kotlin_com_google_code_findbugs_jsr305", "actual": "@io_bazel_rules_kotlin_com_google_code_findbugs_jsr305//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/code/findbugs/jsr305"}, {"artifact": "com.google.code.gson:gson:2.7", "lang": "java", "sha1": "751f548c85fa49f330cecbb1875893f971b33c4e", "sha256": "2d43eb5ea9e133d2ee2405cc14f5ee08951b8361302fdd93494a3a997b508d32", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/code/gson/gson/2.7/gson-2.7.jar", "source": {"sha1": "bbb63ca253b483da8ee53a50374593923e3de2e2", "sha256": "2d3220d5d936f0a26258aa3b358160741a4557e046a001251e5799c2db0f0d74", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/code/gson/gson/2.7/gson-2.7-sources.jar"} , "name": "io_bazel_rules_kotlin_com_google_code_gson_gson", "actual": "@io_bazel_rules_kotlin_com_google_code_gson_gson//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/code/gson/gson"}, {"artifact": "com.google.dagger:dagger-compiler:2.16", "lang": "java", "sha1": "203235b0c6875c39a0b5053dfc2f043acab04acf", "sha256": "723dca807605ddc82cd86c4e334493789ad7fb3fe863b264a8853611c89baf3d", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/dagger/dagger-compiler/2.16/dagger-compiler-2.16.jar", "source": {"sha1": "7ceeb0333370b3f0c28f4b23b1db72d8aae5efa3", "sha256": "05dbe0867bd1efce9a446359d30a0ad2bfe0407b1afd2b31a3058944d2bf3a7d", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/dagger/dagger-compiler/2.16/dagger-compiler-2.16-sources.jar"} , "name": "io_bazel_rules_kotlin_com_google_dagger_dagger_compiler", "actual": "@io_bazel_rules_kotlin_com_google_dagger_dagger_compiler//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/dagger/dagger_compiler"}, {"artifact": "com.google.dagger:dagger-producers:2.16", "lang": "java", "sha1": "4e084a99b71a31e7079603c9675cb4994aff1344", "sha256": "97737907bde6e94cfa90883fa2a8ff4765400b9561bdcb4d83fe475ddbaf22af", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/dagger/dagger-producers/2.16/dagger-producers-2.16.jar", "source": {"sha1": "b477b4eebb171e718c7c9c4e4968913e50cf8e52", "sha256": "93838ce482666e54ed7a10d97558db99fce7c761392db44c259805e66664f384", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/dagger/dagger-producers/2.16/dagger-producers-2.16-sources.jar"} , "name": "io_bazel_rules_kotlin_com_google_dagger_dagger_producers", "actual": "@io_bazel_rules_kotlin_com_google_dagger_dagger_producers//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/dagger/dagger_producers"},