develop builder testing base classes further
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/BUILD b/src/test/kotlin/io/bazel/kotlin/builder/BUILD
index ee20997..9a554b2 100644
--- a/src/test/kotlin/io/bazel/kotlin/builder/BUILD
+++ b/src/test/kotlin/io/bazel/kotlin/builder/BUILD
@@ -27,6 +27,7 @@
     name = "test_lib",
     testonly = 1,
     srcs = [
+        "Dep.java",
         "KotlinBuilderJsTestTask.java",
         "KotlinBuilderJvmTestTask.java",
         "KotlinBuilderResource.java",
@@ -43,7 +44,9 @@
         "@com_github_jetbrains_kotlin//:kotlin-reflect",
         "@com_github_jetbrains_kotlin//:kotlin-stdlib",
     ],
-    deps = _COMMON_DEPS,
+    deps = _COMMON_DEPS + [
+        "//third_party:autovalue",
+    ],
 )
 
 kt_rules_test(
@@ -57,16 +60,21 @@
 )
 
 kt_rules_test(
-    name = "KotlinBuilderJvmTest",
-    srcs = ["tasks/jvm/KotlinBuilderJvmTest.java"],
+    name = "KotlinBuilderJvmBasicTest",
+    srcs = ["tasks/jvm/KotlinBuilderJvmBasicTest.java"],
+)
+
+kt_rules_test(
+    name = "KotlinBuilderJvmKaptTest",
+    srcs = ["tasks/jvm/KotlinBuilderJvmKaptTest.java"],
     data = [
         "//third_party/jvm/com/google/auto/value:auto_value",
-    ],
+    ]
 )
 
 kt_rules_test(
     name = "KotlinBuilderJsTest",
-    srcs = ["tasks/js/KotlinBuilderJsTest.java"],
+    srcs = ["tasks/js/KotlinBuilderJsTest.java"]
 )
 
 test_suite(
@@ -74,7 +82,8 @@
     tests = [
         ":JdepsParserTest",
         ":KotlinBuilderJsTest",
-        ":KotlinBuilderJvmTest",
+        ":KotlinBuilderJvmKaptTest",
+        ":KotlinBuilderJvmBasicTest",
         ":SourceJarCreatorTest",
     ],
     visibility = ["//visibility:public"],
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/Dep.java b/src/test/kotlin/io/bazel/kotlin/builder/Dep.java
new file mode 100644
index 0000000..4a3e1d4
--- /dev/null
+++ b/src/test/kotlin/io/bazel/kotlin/builder/Dep.java
@@ -0,0 +1,78 @@
+/*
+ * 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.auto.value.AutoValue;
+import com.google.common.collect.ImmutableSet;
+import io.bazel.kotlin.builder.utils.BazelRunFiles;
+
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Stream;
+
+@SuppressWarnings({"WeakerAccess", "unused"})
+@AutoValue
+public abstract class Dep {
+  public abstract String label();
+
+  public abstract String moduleName();
+
+  public abstract Set<String> runtimeDeps();
+
+  public abstract Set<String> compileJars();
+
+  public static Builder builder() {
+    return new AutoValue_Dep.Builder().runtimeDeps(ImmutableSet.of());
+  }
+
+  @SuppressWarnings("UnusedReturnValue")
+  @AutoValue.Builder
+  public abstract static class Builder {
+    public abstract Builder compileJars(Set<String> compileJars);
+
+    public abstract Builder label(String label);
+
+    public abstract Builder runtimeDeps(Set<String> runtimeDeps);
+
+    public abstract Builder moduleName(String moduleName);
+
+    abstract String label();
+
+    abstract Optional<String> moduleName();
+
+    abstract Dep autoBuild();
+
+    public Dep build() {
+      if (!moduleName().isPresent()) {
+        moduleName(label());
+      }
+      return autoBuild();
+    }
+  }
+
+  /** Collect all of the compile jars of all the dependencies. */
+  public static Stream<String> classpathOf(Dep... dependencies) {
+    return Stream.of(dependencies).flatMap(it -> it.compileJars().stream());
+  }
+
+  /** Import a single dep. Similar to a `kt_jvm_import` or a `kt_js_import`. */
+  public static Dep importJar(String label, String compileJar) {
+    return Dep.builder()
+        .label(label)
+        .compileJars(ImmutableSet.of(BazelRunFiles.resolveVerified(compileJar).getAbsolutePath()))
+        .build();
+  }
+}
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderJsTestTask.java b/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderJsTestTask.java
index ed5e822..ff65016 100644
--- a/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderJsTestTask.java
+++ b/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderJsTestTask.java
@@ -1,5 +1,21 @@
+/*
+ * 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 io.bazel.kotlin.builder.toolchain.KotlinToolchain;
 import io.bazel.kotlin.model.CompilationTaskInfo;
 import io.bazel.kotlin.model.JsCompilationTask;
 
@@ -11,6 +27,8 @@
   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() {
@@ -39,4 +57,19 @@
     Path sourcePath = super.writeSourceFile(filename, lines);
     taskBuilder.getInputsBuilder().addKotlinSources(sourcePath.toString());
   }
+
+  public void runCompilationTask() {
+    runCompileTask(
+        (taskContext, task) -> {
+          component.jsTaskExecutor().execute(taskContext, task);
+          String jsFile = task.getOutputs().getJs();
+          assertFilesExist(
+              jsFile,
+              jsFile + ".map",
+              jsFile.substring(0, jsFile.length() - 3) + ".meta.js",
+              task.getOutputs().getJar(),
+              task.getOutputs().getSrcjar());
+          return null;
+        });
+  }
 }
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderJvmTestTask.java b/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderJvmTestTask.java
index bc80def..e2c294f 100644
--- a/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderJvmTestTask.java
+++ b/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderJvmTestTask.java
@@ -1,13 +1,53 @@
+/*
+ * 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.collect.ImmutableSet;
+import io.bazel.kotlin.builder.toolchain.KotlinToolchain;
 import io.bazel.kotlin.model.AnnotationProcessor;
 import io.bazel.kotlin.model.CompilationTaskInfo;
 import io.bazel.kotlin.model.JvmCompilationTask;
 
 import java.util.Arrays;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 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() {
@@ -20,7 +60,7 @@
   }
 
   @Override
-  protected void before() throws Throwable {
+  protected final void before() throws Throwable {
     taskBuilder.clear();
     super.before();
 
@@ -38,6 +78,14 @@
         .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")) {
@@ -57,12 +105,34 @@
   }
 
   public void addDirectDependencies(Dep... dependencies) {
-    Dep.merge(dependencies)
-        .compileJars()
-        .forEach(
-            (dependency) ->
-                taskBuilder
-                    .getInputsBuilder()
-                    .addClasspath(dependency));
+    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/KotlinBuilderResource.java b/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderResource.java
index 699104f..3b66a12 100644
--- a/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderResource.java
+++ b/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderResource.java
@@ -1,10 +1,27 @@
+/*
+ * 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 io.bazel.kotlin.builder.toolchain.CompilationException;
 import io.bazel.kotlin.builder.toolchain.CompilationStatusException;
-import io.bazel.kotlin.builder.utils.BazelRunFiles;
 import io.bazel.kotlin.builder.utils.CompilationTaskContext;
-import io.bazel.kotlin.model.*;
+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 java.io.*;
@@ -17,7 +34,6 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.BiConsumer;
 import java.util.function.BiFunction;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
@@ -49,51 +65,9 @@
     }
   }
 
-  public abstract static class Dep {
-    private Dep() {}
-
-    abstract Stream<String> compileJars();
-
-    private static class Simple extends Dep {
-      private final List<String> compileJars;
-
-      private Simple(List<String> compileJars) {
-        this.compileJars = compileJars;
-      }
-
-      @Override
-      Stream<String> compileJars() {
-        return compileJars.stream();
-      }
-    }
-
-    static Dep merge(Dep... dependencies) {
-      return new Simple(
-          Stream.of(dependencies).flatMap(Dep::compileJars).collect(Collectors.toList()));
-    }
-
-    public static List<String> classpathOf(Dep... dependencies) {
-      return merge(dependencies).compileJars().collect(Collectors.toList());
-    }
-
-    public static Dep simpleOf(String compileJar) {
-      return new Simple(
-          Collections.singletonList(BazelRunFiles.resolveVerified(compileJar).getAbsolutePath()));
-    }
-  }
-
   private static final Path
       BAZEL_TEST_DIR = Paths.get(Objects.requireNonNull(System.getenv("TEST_TMPDIR"))),
       EXTERNAL_PATH = Paths.get("external");
-  @SuppressWarnings("unused")
-  public static Dep
-      KOTLIN_ANNOTATIONS =
-          Dep.simpleOf("external/com_github_jetbrains_kotlin/lib/annotations-13.0.jar"),
-      KOTLIN_STDLIB = Dep.simpleOf("external/com_github_jetbrains_kotlin/lib/kotlin-stdlib.jar"),
-      KOTLIN_STDLIB_JDK7 =
-          Dep.simpleOf("external/com_github_jetbrains_kotlin/lib/kotlin-stdlib-jdk7.jar"),
-      KOTLIN_STDLIB_JDK8 =
-          Dep.simpleOf("external/com_github_jetbrains_kotlin/lib/kotlin-stdlib-jdk8.jar");
 
   private static final AtomicInteger counter = new AtomicInteger(0);
   private static final int DEFAULT_TIMEOUT = 10;
@@ -233,21 +207,10 @@
     }
   }
 
-  public final void runCompileTask(BiConsumer<CompilationTaskContext, T> operation) {
+  final <R> R runCompileTask(BiFunction<CompilationTaskContext, T, R> operation) {
     CompilationTaskInfo info = infoBuilder().build();
     T task = buildTask();
-    runCompileTask(
-        info,
-        task,
-        (ctx, t) -> {
-          operation.accept(ctx, task);
-          return null;
-        });
-  }
-
-  @SuppressWarnings("unused")
-  public final <R> R runCompileTask(BiFunction<CompilationTaskContext, T, R> operation) {
-    return runCompileTask(infoBuilder().build(), buildTask(), operation);
+    return runCompileTask(info, task, (ctx, t) -> operation.apply(ctx, task));
   }
 
   /**
@@ -257,9 +220,9 @@
    * @param validator a consumer for the output produced by the task.
    */
   public final void runFailingCompileTaskAndValidateOutput(
-      BiConsumer<CompilationTaskContext, T> task, Consumer<List<String>> validator) {
+      Runnable task, Consumer<List<String>> validator) {
     try {
-      runCompileTask(task);
+      task.run();
     } catch (CompilationStatusException ex) {
       validator.accept(outLines());
       return;
@@ -271,7 +234,7 @@
     assertFileExistence(resolved(dir, paths), true);
   }
 
-  public final void assertFilesExist(String... paths) {
+  final void assertFilesExist(String... paths) {
     assertFileExistence(Stream.of(paths).map(Paths::get), true);
   }
 
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 de300cf..41c2ef6 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,11 +1,6 @@
 package io.bazel.kotlin.builder.tasks.js;
 
-import io.bazel.kotlin.builder.DaggerKotlinBuilderComponent;
-import io.bazel.kotlin.builder.KotlinBuilderComponent;
 import io.bazel.kotlin.builder.KotlinBuilderJsTestTask;
-import io.bazel.kotlin.builder.toolchain.KotlinToolchain;
-import io.bazel.kotlin.builder.utils.CompilationTaskContext;
-import io.bazel.kotlin.model.JsCompilationTask;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -17,31 +12,17 @@
 public class KotlinBuilderJsTest {
   @Rule public KotlinBuilderJsTestTask ctx = new KotlinBuilderJsTestTask();
 
-  private static final KotlinBuilderComponent component =
-      DaggerKotlinBuilderComponent.builder().toolchain(KotlinToolchain.createToolchain()).build();
-
   @Test
   public void testSimpleJsCompile() {
     ctx.addSource("AClass.kt", "package something", "class AClass{}");
-    ctx.runCompileTask(this::jsCompilationTask);
+    ctx.runCompilationTask();
   }
 
   @Test
   public void testJsErrorRendering() {
     ctx.addSource("AClass.kt", "package something", "class AClass{");
     ctx.runFailingCompileTaskAndValidateOutput(
-        this::jsCompilationTask,
+        ctx::runCompilationTask,
         lines -> assertThat(lines.get(0)).startsWith(ctx.toPlatform("sources/AClass.kt")));
   }
-
-  private void jsCompilationTask(CompilationTaskContext taskContext, JsCompilationTask task) {
-    component.jsTaskExecutor().execute(taskContext, task);
-    String jsFile = task.getOutputs().getJs();
-    ctx.assertFilesExist(
-        jsFile,
-        jsFile + ".map",
-        jsFile.substring(0, jsFile.length() - 3) + ".meta.js",
-        task.getOutputs().getJar(),
-        task.getOutputs().getSrcjar());
-  }
 }
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
new file mode 100644
index 0000000..ffe49ce
--- /dev/null
+++ b/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinBuilderJvmBasicTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.tasks.jvm;
+
+import io.bazel.kotlin.builder.KotlinBuilderJvmTestTask;
+import io.bazel.kotlin.builder.KotlinBuilderResource.DirectoryType;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(JUnit4.class)
+public class KotlinBuilderJvmBasicTest {
+  @Rule public KotlinBuilderJvmTestTask ctx = new KotlinBuilderJvmTestTask();
+
+  @Test
+  public void testSimpleMixedModeCompile() {
+    ctx.addSource("AClass.kt", "package something;" + "class AClass{}");
+    ctx.addSource("AnotherClass.java", "package something;", "", "class AnotherClass{}");
+    ctx.runCompileTask();
+    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.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,
+        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,
+        lines -> assertThat(lines.get(0)).startsWith(ctx.toPlatform("sources/AnotherClass")));
+  }
+
+  @Test
+  @Ignore("The Kotlin compiler expects a single kotlin file at least.")
+  public void testCompileSingleJavaFile() {
+    ctx.runCompileTask(
+        (c) -> c.addSource("AnotherClass.java", "package something;", "", "class AnotherClass{}"));
+  }
+}
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
new file mode 100644
index 0000000..c3ca842
--- /dev/null
+++ b/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinBuilderJvmKaptTest.java
@@ -0,0 +1,144 @@
+/*
+ * 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.tasks.jvm;
+
+import io.bazel.kotlin.builder.Dep;
+import io.bazel.kotlin.builder.KotlinBuilderJvmTestTask;
+import io.bazel.kotlin.builder.KotlinBuilderResource;
+import io.bazel.kotlin.model.AnnotationProcessor;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+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;
+
+@RunWith(JUnit4.class)
+public class KotlinBuilderJvmKaptTest {
+  private static final Dep AUTO_VALUE =
+      Dep.importJar(
+          "autovalue",
+          "external/io_bazel_rules_kotlin_com_google_auto_value_auto_value"
+              + "/jar/io_bazel_rules_kotlin_com_google_auto_value_auto_value.jar");
+  private static final AnnotationProcessor AUTO_VALUE_ANNOTATION_PROCESSOR =
+      AnnotationProcessor.newBuilder()
+          .setLabel("autovalue")
+          .setProcessorClass("com.google.auto.value.processor.AutoValueProcessor")
+          .addAllClasspath(
+              Dep.classpathOf(AUTO_VALUE, KOTLIN_ANNOTATIONS).collect(Collectors.toList()))
+          .build();
+
+  @Rule public KotlinBuilderJvmTestTask ctx = new KotlinBuilderJvmTestTask();
+
+  private static final Consumer<KotlinBuilderJvmTestTask> ADD_AUTO_VALUE_PLUGIN =
+      (c) -> {
+        c.addAnnotationProcessors(AUTO_VALUE_ANNOTATION_PROCESSOR);
+        c.addDirectDependencies(AUTO_VALUE, KOTLIN_STDLIB);
+      };
+
+  @Test
+  public void testKaptKt() {
+    ctx.runCompileTask(
+        ADD_AUTO_VALUE_PLUGIN,
+        c ->
+            c.addSource(
+                "TestKtValue.kt",
+                "package autovalue\n"
+                    + "\n"
+                    + "import com.google.auto.value.AutoValue\n"
+                    + "\n"
+                    + "@AutoValue\n"
+                    + "abstract class TestKtValue {\n"
+                    + "    abstract fun name(): String\n"
+                    + "    fun builder(): Builder = AutoValue_TestKtValue.Builder()\n"
+                    + "\n"
+                    + "    @AutoValue.Builder\n"
+                    + "    abstract class Builder {\n"
+                    + "        abstract fun setName(name: String): Builder\n"
+                    + "        abstract fun build(): TestKtValue\n"
+                    + "    }\n"
+                    + "}"));
+
+    ctx.assertFilesExist(
+        KotlinBuilderResource.DirectoryType.CLASSES,
+        "autovalue/TestKtValue.class",
+        "autovalue/AutoValue_TestKtValue.class");
+    ctx.assertFilesExist(
+        KotlinBuilderResource.DirectoryType.SOURCE_GEN, "autovalue/AutoValue_TestKtValue.java");
+  }
+
+  @Test
+  public void testMixedKaptBiReferences() {
+    ctx.runCompileTask(
+        ADD_AUTO_VALUE_PLUGIN,
+        ctx -> {
+          ctx.addSource(
+              "TestKtValue.kt",
+              "package autovalue.a\n"
+                  + "\n"
+                  + "import com.google.auto.value.AutoValue\n"
+                  + "import autovalue.b.TestAutoValue\n"
+                  + "\n"
+                  + "@AutoValue\n"
+                  + "abstract class TestKtValue {\n"
+                  + "    abstract fun name(): String\n"
+                  + "    fun builder(): Builder = AutoValue_TestKtValue.Builder()\n"
+                  + "\n"
+                  + "    @AutoValue.Builder\n"
+                  + "    abstract class Builder {\n"
+                  + "        abstract fun setName(name: String): Builder\n"
+                  + "        abstract fun build(): TestKtValue\n"
+                  + "    }\n"
+                  + "}");
+
+          ctx.addSource(
+              "TestAutoValue.java",
+              "package autovalue.b;\n"
+                  + "\n"
+                  + "import com.google.auto.value.AutoValue;\n"
+                  + "import autovalue.a.TestKtValue;\n"
+                  + "\n"
+                  + "@AutoValue\n"
+                  + "public abstract class TestAutoValue {\n"
+                  + "    abstract String name();\n"
+                  + "\n"
+                  + "\n"
+                  + "    static Builder builder() {\n"
+                  + "        return new AutoValue_TestAutoValue.Builder();\n"
+                  + "    }\n"
+                  + "\n"
+                  + "    @AutoValue.Builder\n"
+                  + "    abstract static class Builder {\n"
+                  + "        abstract Builder setName(String name);\n"
+                  + "        abstract TestAutoValue build();\n"
+                  + "    }\n"
+                  + "\n"
+                  + "}");
+        });
+    ctx.assertFilesExist(
+        KotlinBuilderResource.DirectoryType.SOURCE_GEN,
+        "autovalue/a/AutoValue_TestKtValue.java",
+        "autovalue/b/AutoValue_TestAutoValue.java");
+    ctx.assertFilesExist(
+        KotlinBuilderResource.DirectoryType.CLASSES,
+        "autovalue/a/AutoValue_TestKtValue.class",
+        "autovalue/b/AutoValue_TestAutoValue.class");
+  }
+}
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinBuilderJvmTest.java b/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinBuilderJvmTest.java
deleted file mode 100644
index 3fff0e0..0000000
--- a/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinBuilderJvmTest.java
+++ /dev/null
@@ -1,185 +0,0 @@
-package io.bazel.kotlin.builder.tasks.jvm;
-
-import io.bazel.kotlin.builder.DaggerKotlinBuilderComponent;
-import io.bazel.kotlin.builder.KotlinBuilderComponent;
-import io.bazel.kotlin.builder.KotlinBuilderJvmTestTask;
-import io.bazel.kotlin.builder.KotlinBuilderResource.Dep;
-import io.bazel.kotlin.builder.KotlinBuilderResource.DirectoryType;
-import io.bazel.kotlin.builder.toolchain.KotlinToolchain;
-import io.bazel.kotlin.builder.utils.CompilationTaskContext;
-import io.bazel.kotlin.model.AnnotationProcessor;
-import io.bazel.kotlin.model.JvmCompilationTask;
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
-
-import static com.google.common.truth.Truth.assertThat;
-import static io.bazel.kotlin.builder.KotlinBuilderResource.KOTLIN_ANNOTATIONS;
-import static io.bazel.kotlin.builder.KotlinBuilderResource.KOTLIN_STDLIB;
-
-public class KotlinBuilderJvmTest {
-  private static Dep AUTO_VALUE =
-      Dep.simpleOf(
-          "external/io_bazel_rules_kotlin_com_google_auto_value_auto_value"
-              + "/jar/io_bazel_rules_kotlin_com_google_auto_value_auto_value.jar");
-
-  private static final AnnotationProcessor AUTO_VALUE_ANNOTATION_PROCESSOR =
-      AnnotationProcessor.newBuilder()
-          .setLabel("autovalue")
-          .setProcessorClass("com.google.auto.value.processor.AutoValueProcessor")
-          .addAllClasspath(Dep.classpathOf(AUTO_VALUE, KOTLIN_ANNOTATIONS))
-          .build();
-
-  private static final KotlinBuilderComponent component =
-      DaggerKotlinBuilderComponent.builder().toolchain(KotlinToolchain.createToolchain()).build();
-
-  @Rule public KotlinBuilderJvmTestTask ctx = new KotlinBuilderJvmTestTask();
-
-  @Test
-  public void testSimpleMixedModeCompile() {
-    ctx.addSource("AClass.kt", "package something;" + "class AClass{}");
-    ctx.addSource("AnotherClass.java", "package something;", "", "class AnotherClass{}");
-    ctx.runCompileTask(this::jvmCompilationTask);
-    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(this::jvmCompilationTask);
-    ctx.assertFilesExist(DirectoryType.CLASSES, "a/AClass.class", "b/BClass.class");
-  }
-
-  @Test
-  public void testKaptKt() {
-    ctx.addSource(
-        "TestKtValue.kt",
-        "package autovalue\n"
-            + "\n"
-            + "import com.google.auto.value.AutoValue\n"
-            + "\n"
-            + "@AutoValue\n"
-            + "abstract class TestKtValue {\n"
-            + "    abstract fun name(): String\n"
-            + "    fun builder(): Builder = AutoValue_TestKtValue.Builder()\n"
-            + "\n"
-            + "    @AutoValue.Builder\n"
-            + "    abstract class Builder {\n"
-            + "        abstract fun setName(name: String): Builder\n"
-            + "        abstract fun build(): TestKtValue\n"
-            + "    }\n"
-            + "}");
-    ctx.addAnnotationProcessors(AUTO_VALUE_ANNOTATION_PROCESSOR);
-    ctx.addDirectDependencies(AUTO_VALUE, KOTLIN_STDLIB);
-    ctx.runCompileTask(this::jvmCompilationTask);
-    ctx.assertFilesExist(
-        DirectoryType.CLASSES,
-        "autovalue/TestKtValue.class",
-        "autovalue/AutoValue_TestKtValue.class");
-    ctx.assertFilesExist(DirectoryType.SOURCE_GEN, "autovalue/AutoValue_TestKtValue.java");
-  }
-
-  @Test
-  public void testMixedKaptBiReferences() {
-    ctx.addSource(
-        "TestKtValue.kt",
-        "package autovalue.a\n"
-            + "\n"
-            + "import com.google.auto.value.AutoValue\n"
-            + "import autovalue.b.TestAutoValue\n"
-            + "\n"
-            + "@AutoValue\n"
-            + "abstract class TestKtValue {\n"
-            + "    abstract fun name(): String\n"
-            + "    fun builder(): Builder = AutoValue_TestKtValue.Builder()\n"
-            + "\n"
-            + "    @AutoValue.Builder\n"
-            + "    abstract class Builder {\n"
-            + "        abstract fun setName(name: String): Builder\n"
-            + "        abstract fun build(): TestKtValue\n"
-            + "    }\n"
-            + "}");
-    ctx.addSource(
-        "TestAutoValue.java",
-        "package autovalue.b;\n"
-            + "\n"
-            + "import com.google.auto.value.AutoValue;\n"
-            + "import autovalue.a.TestKtValue;\n"
-            + "\n"
-            + "@AutoValue\n"
-            + "public abstract class TestAutoValue {\n"
-            + "    abstract String name();\n"
-            + "\n"
-            + "\n"
-            + "    static Builder builder() {\n"
-            + "        return new AutoValue_TestAutoValue.Builder();\n"
-            + "    }\n"
-            + "\n"
-            + "    @AutoValue.Builder\n"
-            + "    abstract static class Builder {\n"
-            + "        abstract Builder setName(String name);\n"
-            + "        abstract TestAutoValue build();\n"
-            + "    }\n"
-            + "\n"
-            + "}");
-
-    ctx.addAnnotationProcessors(AUTO_VALUE_ANNOTATION_PROCESSOR);
-    ctx.addDirectDependencies(AUTO_VALUE, KOTLIN_STDLIB);
-    ctx.runCompileTask(this::jvmCompilationTask);
-    ctx.assertFilesExist(
-        DirectoryType.SOURCE_GEN,
-        "autovalue/a/AutoValue_TestKtValue.java",
-        "autovalue/b/AutoValue_TestAutoValue.java");
-    ctx.assertFilesExist(
-        DirectoryType.CLASSES,
-        "autovalue/a/AutoValue_TestKtValue.class",
-        "autovalue/b/AutoValue_TestAutoValue.class");
-  }
-
-  @Test
-  public void testKotlinErrorRendering() {
-    ctx.addSource("AClass.kt", "package something;" + "class AClass{");
-    ctx.runFailingCompileTaskAndValidateOutput(
-        this::jvmCompilationTask,
-        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(
-        this::jvmCompilationTask,
-        lines -> assertThat(lines.get(0)).startsWith(ctx.toPlatform("sources/AnotherClass")));
-  }
-
-  @Test
-  @Ignore("The Kotlin compiler expects a single kotlin file at least.")
-  public void testCompileSingleJavaFile() {
-    ctx.addSource("AnotherClass.java", "package something;", "", "class AnotherClass{}");
-    ctx.runCompileTask(this::jvmCompilationTask);
-  }
-
-  private void jvmCompilationTask(CompilationTaskContext taskContext, JvmCompilationTask task) {
-    component.jvmTaskExecutor().execute(taskContext, task);
-    ctx.assertFilesExist(task.getOutputs().getJar(), task.getOutputs().getJdeps());
-  }
-}
diff --git a/third_party/BUILD b/third_party/BUILD
index 3e01d88..d585557 100644
--- a/third_party/BUILD
+++ b/third_party/BUILD
@@ -29,6 +29,21 @@
 )
 
 java_plugin(
+    name = "autovalue_plugin",
+    generates_api = 1,
+    processor_class = "com.google.auto.value.processor.AutoValueProcessor",
+    visibility = ["//visibility:private"],
+    deps = ["//third_party/jvm/com/google/auto/value:auto_value"],
+)
+
+java_library(
+    name = "autovalue",
+    exported_plugins = [":autovalue_plugin"],
+    neverlink = 1,
+    exports = ["//third_party/jvm/com/google/auto/value:auto_value"],
+)
+
+java_plugin(
     name = "dagger_component_plugin",
     generates_api = 1,
     processor_class = "dagger.internal.codegen.ComponentProcessor",