Merge "Include raw output in processor tests" into androidx-main
diff --git a/room/compiler-processing-testing/src/main/java/androidx/room/compiler/processing/SyntheticJavacProcessor.kt b/room/compiler-processing-testing/src/main/java/androidx/room/compiler/processing/SyntheticJavacProcessor.kt
index 54fc124..8e57001 100644
--- a/room/compiler-processing-testing/src/main/java/androidx/room/compiler/processing/SyntheticJavacProcessor.kt
+++ b/room/compiler-processing-testing/src/main/java/androidx/room/compiler/processing/SyntheticJavacProcessor.kt
@@ -48,15 +48,14 @@
 
     override fun getSupportedAnnotationTypes() = setOf("*")
 
-    override fun throwIfFailed() {
-        val result = checkNotNull(result) {
-            "did not compile"
+    override fun getProcessingException(): Throwable? {
+        val result = this.result ?: return AssertionError("processor didn't run")
+        result.exceptionOrNull()?.let {
+            return it
         }
         if (result.isFailure) {
-            // throw AssertionError instead of re-throwing the same error to keep the stack trace
-            // of the failure in the exception's cause field. We cannot throw it as is since stack
-            // traces do not match.
-            throw AssertionError(result.exceptionOrNull()!!)
+            return AssertionError("processor failed but no exception is reported")
         }
+        return null
     }
 }
\ No newline at end of file
diff --git a/room/compiler-processing-testing/src/main/java/androidx/room/compiler/processing/SyntheticKspProcessor.kt b/room/compiler-processing-testing/src/main/java/androidx/room/compiler/processing/SyntheticKspProcessor.kt
index 68ec813..77ea907 100644
--- a/room/compiler-processing-testing/src/main/java/androidx/room/compiler/processing/SyntheticKspProcessor.kt
+++ b/room/compiler-processing-testing/src/main/java/androidx/room/compiler/processing/SyntheticKspProcessor.kt
@@ -66,12 +66,14 @@
         }
     }
 
-    override fun throwIfFailed() {
-        val result = checkNotNull(result) {
-            "did not compile"
+    override fun getProcessingException(): Throwable? {
+        val result = this.result ?: return AssertionError("processor didn't run")
+        result.exceptionOrNull()?.let {
+            return it
         }
         if (result.isFailure) {
-            throw result.exceptionOrNull()!!
+            return AssertionError("processor failed but no exception is reported")
         }
+        return null
     }
 }
diff --git a/room/compiler-processing-testing/src/main/java/androidx/room/compiler/processing/SyntheticProcessor.kt b/room/compiler-processing-testing/src/main/java/androidx/room/compiler/processing/SyntheticProcessor.kt
index 05cc826..a9872df9a 100644
--- a/room/compiler-processing-testing/src/main/java/androidx/room/compiler/processing/SyntheticProcessor.kt
+++ b/room/compiler-processing-testing/src/main/java/androidx/room/compiler/processing/SyntheticProcessor.kt
@@ -37,9 +37,10 @@
     val messageWatcher: RecordingXMessager
 
     /**
-     * Should throw if processor did throw an exception.
+     * Should return any assertion error that happened during processing.
+     *
      * When assertions fail, we don't fail the compilation to keep the stack trace, instead,
      * dispatch them afterwards.
      */
-    fun throwIfFailed()
+    fun getProcessingException(): Throwable?
 }
diff --git a/room/compiler-processing-testing/src/main/java/androidx/room/compiler/processing/util/CompilationResultSubject.kt b/room/compiler-processing-testing/src/main/java/androidx/room/compiler/processing/util/CompilationResultSubject.kt
index 3dbbff7..c54b005 100644
--- a/room/compiler-processing-testing/src/main/java/androidx/room/compiler/processing/util/CompilationResultSubject.kt
+++ b/room/compiler-processing-testing/src/main/java/androidx/room/compiler/processing/util/CompilationResultSubject.kt
@@ -50,6 +50,14 @@
 
     fun diagnosticsOfKind(kind: Diagnostic.Kind) = diagnostics[kind].orEmpty()
 
+    /**
+     * We report only errors reported via room diagnostics which means we might miss other
+     * compiler errors, warnings etc. This output is free-text for compilers to print whatever is
+     * relevant to them. Note that not including non-room diagnostic errors do not impact
+     * correctness as we always assert compilation result.
+     */
+    abstract fun rawOutput(): String
+
     override fun toString(): String {
         return buildString {
             appendLine("CompilationResult (with $testRunnerName)")
@@ -61,6 +69,8 @@
                 }
                 appendLine()
             }
+            appendLine("RAW OUTPUT:")
+            appendLine(rawOutput())
         }
     }
 }
@@ -149,6 +159,19 @@
         }
     }
 
+    internal fun assertNoProcessorAssertionErrors() {
+        val processingException = compilationResult.processor.getProcessingException()
+        if (processingException != null) {
+            // processor has an error which we want to throw but we also want the subject, hence
+            // we wrap it
+            throw AssertionError(
+                "Processor reported an error. See the cause for details\n" +
+                    "$compilationResult",
+                processingException
+            )
+        }
+    }
+
     private fun hasDiagnosticWithMessage(
         kind: Diagnostic.Kind,
         expected: String,
@@ -195,7 +218,13 @@
     testRunnerName = testRunner.name,
     processor = processor,
     successfulCompilation = delegate.status() == Compilation.Status.SUCCESS
-)
+) {
+    override fun rawOutput(): String {
+        return delegate.diagnostics().joinToString {
+            it.toString()
+        }
+    }
+}
 
 internal class KotlinCompileTestingCompilationResult(
     testRunner: CompilationTestRunner,
@@ -207,4 +236,8 @@
     testRunnerName = testRunner.name,
     processor = processor,
     successfulCompilation = successfulCompilation
-)
\ No newline at end of file
+) {
+    override fun rawOutput(): String {
+        return delegate.messages
+    }
+}
\ No newline at end of file
diff --git a/room/compiler-processing-testing/src/main/java/androidx/room/compiler/processing/util/ProcessorTestExt.kt b/room/compiler-processing-testing/src/main/java/androidx/room/compiler/processing/util/ProcessorTestExt.kt
index bbf2888..b4beb39 100644
--- a/room/compiler-processing-testing/src/main/java/androidx/room/compiler/processing/util/ProcessorTestExt.kt
+++ b/room/compiler-processing-testing/src/main/java/androidx/room/compiler/processing/util/ProcessorTestExt.kt
@@ -35,8 +35,7 @@
             val compilationResult = runner.compile(params)
             val subject = CompilationResultSubject.assertThat(compilationResult)
             // if any assertion failed, throw first those.
-            compilationResult.processor.throwIfFailed()
-
+            subject.assertNoProcessorAssertionErrors()
             compilationResult.processor.invocationInstances.forEach {
                 it.runPostCompilationChecks(subject)
             }
diff --git a/room/compiler-processing-testing/src/test/java/androidx/room/compiler/processing/util/TestRunnerTest.kt b/room/compiler-processing-testing/src/test/java/androidx/room/compiler/processing/util/TestRunnerTest.kt
index 59dd47f7..def43fd 100644
--- a/room/compiler-processing-testing/src/test/java/androidx/room/compiler/processing/util/TestRunnerTest.kt
+++ b/room/compiler-processing-testing/src/test/java/androidx/room/compiler/processing/util/TestRunnerTest.kt
@@ -16,6 +16,7 @@
 
 package androidx.room.compiler.processing.util
 
+import com.google.common.truth.Truth.assertThat
 import com.squareup.javapoet.CodeBlock
 import com.squareup.javapoet.JavaFile
 import com.squareup.javapoet.TypeSpec
@@ -56,7 +57,7 @@
     @Test(expected = AssertionError::class)
     fun reportedError_unexpected() = reportedError(assertFailure = false)
 
-    fun reportedError(assertFailure: Boolean) {
+    private fun reportedError(assertFailure: Boolean) {
         runProcessorTest {
             it.processingEnv.messager.printMessage(
                 kind = Diagnostic.Kind.ERROR,
@@ -69,4 +70,68 @@
             }
         }
     }
+
+    @Test
+    fun syntacticErrorsAreVisibleInTheErrorMessage_java() {
+        val src = Source.java(
+            "test.Foo",
+            """
+            package test;
+            // static here is invalid, causes a Java syntax error
+            public static class Foo {}
+            """.trimIndent()
+        )
+        val errorMessage = "error: modifier static not allowed here"
+        val javapResult = runCatching {
+            runJavaProcessorTest(
+                sources = listOf(src),
+                classpath = emptyList()
+            ) {}
+        }
+        assertThat(javapResult.exceptionOrNull()).hasMessageThat()
+            .contains(errorMessage)
+
+        val kaptResult = runCatching {
+            runKaptTest(
+                sources = listOf(src)
+            ) {}
+        }
+        assertThat(kaptResult.exceptionOrNull()).hasMessageThat()
+            .contains(errorMessage)
+
+        val kspResult = runCatching {
+            runKspTest(
+                sources = listOf(src)
+            ) {}
+        }
+        assertThat(kspResult.exceptionOrNull()).hasMessageThat()
+            .contains(errorMessage)
+    }
+
+    @Test
+    fun syntacticErrorsAreVisibleInTheErrorMessage_kotlin() {
+        val src = Source.kotlin(
+            "Foo.kt",
+            """
+            package foo;
+            bad code
+            """.trimIndent()
+        )
+        val errorMessage = "Expecting a top level declaration"
+        val kaptResult = runCatching {
+            runKaptTest(
+                sources = listOf(src)
+            ) {}
+        }
+        assertThat(kaptResult.exceptionOrNull()).hasMessageThat()
+            .contains(errorMessage)
+
+        val kspResult = runCatching {
+            runKspTest(
+                sources = listOf(src)
+            ) {}
+        }
+        assertThat(kspResult.exceptionOrNull()).hasMessageThat()
+            .contains(errorMessage)
+    }
 }
\ No newline at end of file