| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * 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 androidx.room.processor |
| |
| import COMMON |
| import androidx.room.Dao |
| import androidx.room.Transaction |
| import androidx.room.compiler.codegen.CodeLanguage |
| import androidx.room.compiler.processing.XTypeElement |
| import androidx.room.compiler.processing.util.Source |
| import androidx.room.compiler.processing.util.XTestInvocation |
| import androidx.room.compiler.processing.util.runProcessorTest |
| import androidx.room.ext.GuavaUtilConcurrentTypeNames.LISTENABLE_FUTURE |
| import androidx.room.ext.KotlinTypeNames.FLOW |
| import androidx.room.ext.LifecyclesTypeNames.COMPUTABLE_LIVE_DATA |
| import androidx.room.ext.LifecyclesTypeNames.LIVE_DATA |
| import androidx.room.ext.ReactiveStreamsTypeNames.PUBLISHER |
| import androidx.room.ext.RxJava2TypeNames |
| import androidx.room.ext.RxJava3TypeNames |
| import androidx.room.testing.context |
| import androidx.room.vo.TransactionMethod |
| import org.hamcrest.CoreMatchers.`is` |
| import org.hamcrest.MatcherAssert.assertThat |
| import org.junit.Test |
| import org.junit.runner.RunWith |
| import org.junit.runners.JUnit4 |
| |
| @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") |
| @RunWith(JUnit4::class) |
| class TransactionMethodProcessorTest { |
| |
| companion object { |
| const val DAO_PREFIX = """ |
| package foo.bar; |
| import androidx.room.*; |
| import java.util.*; |
| import androidx.lifecycle.*; |
| import com.google.common.util.concurrent.*; |
| import org.reactivestreams.*; |
| @Dao |
| abstract class MyClass { |
| """ |
| const val DAO_SUFFIX = "}" |
| } |
| |
| @Test |
| fun simple() { |
| singleTransactionMethod( |
| """ |
| @Transaction |
| public String doInTransaction(int param) { return null; } |
| """ |
| ) { transaction, _ -> |
| assertThat(transaction.jvmName, `is`("doInTransaction")) |
| } |
| } |
| |
| @Test |
| fun modifier_private() { |
| singleTransactionMethod( |
| """ |
| @Transaction |
| private String doInTransaction(int param) { return null; } |
| """ |
| ) { transaction, invocation -> |
| assertThat(transaction.jvmName, `is`("doInTransaction")) |
| invocation.assertCompilationResult { |
| hasErrorContaining( |
| ProcessorErrors.TRANSACTION_METHOD_MODIFIERS |
| ) |
| } |
| } |
| } |
| |
| @Test |
| fun modifier_final() { |
| singleTransactionMethod( |
| """ |
| @Transaction |
| public final String doInTransaction(int param) { return null; } |
| """ |
| ) { transaction, invocation -> |
| assertThat(transaction.jvmName, `is`("doInTransaction")) |
| invocation.assertCompilationResult { |
| hasErrorContaining(ProcessorErrors.TRANSACTION_METHOD_MODIFIERS) |
| } |
| } |
| } |
| |
| @Test |
| fun deferredReturnType_flow() { |
| singleTransactionMethod( |
| """ |
| @Transaction |
| public kotlinx.coroutines.flow.Flow<String> doInTransaction(int param) { |
| return null; |
| } |
| """ |
| ) { transaction, invocation -> |
| assertThat(transaction.jvmName, `is`("doInTransaction")) |
| invocation.assertCompilationResult { |
| hasErrorContaining( |
| ProcessorErrors.transactionMethodAsync( |
| FLOW.rawTypeName.toString(CodeLanguage.JAVA) |
| ) |
| ) |
| } |
| } |
| } |
| |
| @Test |
| fun deferredReturnType_liveData() { |
| singleTransactionMethod( |
| """ |
| @Transaction |
| public LiveData<String> doInTransaction(int param) { return null; } |
| """ |
| ) { transaction, invocation -> |
| assertThat(transaction.jvmName, `is`("doInTransaction")) |
| invocation.assertCompilationResult { |
| hasErrorContaining( |
| ProcessorErrors.transactionMethodAsync( |
| LIVE_DATA.rawTypeName.toString(CodeLanguage.JAVA) |
| ) |
| ) |
| } |
| } |
| } |
| |
| @Test |
| fun deferredReturnType_computableLiveData() { |
| singleTransactionMethod( |
| """ |
| @Transaction |
| public ComputableLiveData<String> doInTransaction(int param) { return null; } |
| """ |
| ) { transaction, invocation -> |
| assertThat(transaction.jvmName, `is`("doInTransaction")) |
| invocation.assertCompilationResult { |
| hasErrorContaining( |
| ProcessorErrors.transactionMethodAsync( |
| COMPUTABLE_LIVE_DATA.rawTypeName.toString(CodeLanguage.JAVA) |
| ) |
| ) |
| } |
| } |
| } |
| |
| @Test |
| fun deferredReturnType_rx2_flowable() { |
| singleTransactionMethod( |
| """ |
| @Transaction |
| public io.reactivex.Flowable<String> doInTransaction(int param) { return null; } |
| """ |
| ) { transaction, invocation -> |
| assertThat(transaction.jvmName, `is`("doInTransaction")) |
| invocation.assertCompilationResult { |
| hasErrorContaining( |
| ProcessorErrors.transactionMethodAsync( |
| RxJava2TypeNames.FLOWABLE.rawTypeName.toString(CodeLanguage.JAVA) |
| ) |
| ) |
| } |
| } |
| } |
| |
| @Test |
| fun deferredReturnType_rx3_flowable() { |
| singleTransactionMethod( |
| """ |
| @Transaction |
| public io.reactivex.rxjava3.core.Flowable<String> doInTransaction(int param) { |
| return null; |
| } |
| """ |
| ) { transaction, invocation -> |
| assertThat(transaction.jvmName, `is`("doInTransaction")) |
| invocation.assertCompilationResult { |
| hasErrorContaining( |
| ProcessorErrors.transactionMethodAsync( |
| RxJava3TypeNames.FLOWABLE.rawTypeName.toString(CodeLanguage.JAVA) |
| ) |
| ) |
| } |
| } |
| } |
| |
| @Test |
| fun deferredReturnType_rx2_completable() { |
| singleTransactionMethod( |
| """ |
| @Transaction |
| public io.reactivex.Completable doInTransaction(int param) { return null; } |
| """ |
| ) { transaction, invocation -> |
| assertThat(transaction.jvmName, `is`("doInTransaction")) |
| invocation.assertCompilationResult { |
| hasErrorContaining( |
| ProcessorErrors.transactionMethodAsync( |
| RxJava2TypeNames.COMPLETABLE.rawTypeName.toString(CodeLanguage.JAVA) |
| ) |
| ) |
| } |
| } |
| } |
| |
| @Test |
| fun deferredReturnType_rx3_completable() { |
| singleTransactionMethod( |
| """ |
| @Transaction |
| public io.reactivex.rxjava3.core.Completable doInTransaction(int param) { |
| return null; |
| } |
| """ |
| ) { transaction, invocation -> |
| assertThat(transaction.jvmName, `is`("doInTransaction")) |
| invocation.assertCompilationResult { |
| hasErrorContaining( |
| ProcessorErrors.transactionMethodAsync( |
| RxJava3TypeNames.COMPLETABLE.rawTypeName.toString(CodeLanguage.JAVA) |
| ) |
| ) |
| } |
| } |
| } |
| |
| @Test |
| fun deferredReturnType_rx2_single() { |
| singleTransactionMethod( |
| """ |
| @Transaction |
| public io.reactivex.Single<String> doInTransaction(int param) { return null; } |
| """ |
| ) { transaction, invocation -> |
| assertThat(transaction.jvmName, `is`("doInTransaction")) |
| invocation.assertCompilationResult { |
| hasErrorContaining( |
| ProcessorErrors.transactionMethodAsync( |
| RxJava2TypeNames.SINGLE.rawTypeName.toString(CodeLanguage.JAVA) |
| ) |
| ) |
| } |
| } |
| } |
| |
| @Test |
| fun deferredReturnType_rx3_single() { |
| singleTransactionMethod( |
| """ |
| @Transaction |
| public io.reactivex.rxjava3.core.Single<String> doInTransaction(int param) { |
| return null; |
| } |
| """ |
| ) { transaction, invocation -> |
| assertThat(transaction.jvmName, `is`("doInTransaction")) |
| invocation.assertCompilationResult { |
| hasErrorContaining( |
| ProcessorErrors.transactionMethodAsync( |
| RxJava3TypeNames.SINGLE.rawTypeName.toString(CodeLanguage.JAVA) |
| ) |
| ) |
| } |
| } |
| } |
| |
| @Test |
| fun deferredReturnType_listenableFuture() { |
| singleTransactionMethod( |
| """ |
| @Transaction |
| public ListenableFuture<String> doInTransaction(int param) { return null; } |
| """ |
| ) { transaction, invocation -> |
| assertThat(transaction.jvmName, `is`("doInTransaction")) |
| invocation.assertCompilationResult { |
| hasErrorContaining( |
| ProcessorErrors.transactionMethodAsync( |
| LISTENABLE_FUTURE.rawTypeName.toString(CodeLanguage.JAVA) |
| ) |
| ) |
| } |
| } |
| } |
| |
| @Test |
| fun deferredReturnType_publisher() { |
| singleTransactionMethod( |
| """ |
| @Transaction |
| public Publisher<String> doInTransaction(int param) { return null; } |
| """ |
| ) { transaction, invocation -> |
| assertThat(transaction.jvmName, `is`("doInTransaction")) |
| invocation.assertCompilationResult { |
| hasErrorContaining( |
| ProcessorErrors.transactionMethodAsync( |
| PUBLISHER.rawTypeName.toString(CodeLanguage.JAVA) |
| ) |
| ) |
| } |
| } |
| } |
| |
| private val TransactionMethod.jvmName: String |
| get() = element.jvmName |
| |
| private fun singleTransactionMethod( |
| vararg input: String, |
| handler: (TransactionMethod, XTestInvocation) -> Unit |
| ) { |
| val inputSource = listOf( |
| Source.java( |
| "foo.bar.MyClass", |
| DAO_PREFIX + input.joinToString("\n") + DAO_SUFFIX |
| ) |
| ) |
| val otherSources = listOf( |
| COMMON.LIVE_DATA, COMMON.COMPUTABLE_LIVE_DATA, COMMON.RX2_FLOWABLE, COMMON.PUBLISHER, |
| COMMON.RX2_COMPLETABLE, COMMON.RX2_SINGLE, COMMON.RX3_FLOWABLE, COMMON.RX3_COMPLETABLE, |
| COMMON.RX3_SINGLE, COMMON.LISTENABLE_FUTURE, COMMON.FLOW |
| ) |
| runProcessorTest( |
| sources = inputSource + otherSources, |
| options = mapOf(Context.BooleanProcessorOptions.GENERATE_KOTLIN.argName to "false") |
| ) { invocation -> |
| val (owner, methods) = invocation.roundEnv |
| .getElementsAnnotatedWith(Dao::class.qualifiedName!!) |
| .filterIsInstance<XTypeElement>() |
| .map { |
| Pair( |
| it, |
| it.getAllMethods().filter { |
| it.hasAnnotation(Transaction::class) |
| }.toList() |
| ) |
| }.first { it.second.isNotEmpty() } |
| val processor = TransactionMethodProcessor( |
| baseContext = invocation.context, |
| containingElement = owner, |
| containingType = owner.type, |
| executableElement = methods.first() |
| ) |
| val processed = processor.process() |
| handler(processed, invocation) |
| } |
| } |
| } |