1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17import androidx.room.ColumnInfo
18import androidx.room.Embedded
19import androidx.room.Entity
20import androidx.room.PrimaryKey
21import androidx.room.Query
22import androidx.room.Relation
23import androidx.room.ext.LifecyclesTypeNames
24import androidx.room.ext.PagingTypeNames
25import androidx.room.ext.ReactiveStreamsTypeNames
26import androidx.room.ext.RoomRxJava2TypeNames
27import androidx.room.ext.RxJava2TypeNames
28import androidx.room.processor.EntityProcessor
29import androidx.room.solver.CodeGenScope
30import androidx.room.testing.TestInvocation
31import androidx.room.testing.TestProcessor
32import androidx.room.verifier.DatabaseVerifier
33import androidx.room.writer.ClassWriter
34import com.google.auto.common.MoreElements
35import com.google.common.truth.Truth
36import com.google.testing.compile.CompileTester
37import com.google.testing.compile.JavaFileObjects
38import com.google.testing.compile.JavaSourcesSubjectFactory
39import com.squareup.javapoet.ClassName
40import org.mockito.Mockito
41import org.mockito.Mockito.doReturn
42import org.mockito.Mockito.mock
43import java.io.File
44import javax.lang.model.element.Element
45import javax.lang.model.type.TypeKind
46import javax.lang.model.type.TypeMirror
47import javax.tools.JavaFileObject
48
49object COMMON {
50    val USER by lazy {
51        loadJavaCode("common/input/User.java", "foo.bar.User")
52    }
53    val USER_TYPE_NAME by lazy {
54        ClassName.get("foo.bar", "User")
55    }
56    val BOOK by lazy {
57        loadJavaCode("common/input/Book.java", "foo.bar.Book")
58    }
59    val NOT_AN_ENTITY by lazy {
60        loadJavaCode("common/input/NotAnEntity.java", "foo.bar.NotAnEntity")
61    }
62
63    val NOT_AN_ENTITY_TYPE_NAME by lazy {
64        ClassName.get("foo.bar", "NotAnEntity")
65    }
66
67    val MULTI_PKEY_ENTITY by lazy {
68        loadJavaCode("common/input/MultiPKeyEntity.java", "MultiPKeyEntity")
69    }
70    val LIVE_DATA by lazy {
71        loadJavaCode("common/input/LiveData.java", LifecyclesTypeNames.LIVE_DATA.toString())
72    }
73    val COMPUTABLE_LIVE_DATA by lazy {
74        loadJavaCode("common/input/ComputableLiveData.java",
75                LifecyclesTypeNames.COMPUTABLE_LIVE_DATA.toString())
76    }
77    val PUBLISHER by lazy {
78        loadJavaCode("common/input/reactivestreams/Publisher.java",
79                ReactiveStreamsTypeNames.PUBLISHER.toString())
80    }
81    val FLOWABLE by lazy {
82        loadJavaCode("common/input/rxjava2/Flowable.java", RxJava2TypeNames.FLOWABLE.toString())
83    }
84
85    val RX2_ROOM by lazy {
86        loadJavaCode("common/input/Rx2Room.java", RoomRxJava2TypeNames.RX_ROOM.toString())
87    }
88
89    val DATA_SOURCE_FACTORY by lazy {
90        loadJavaCode("common/input/DataSource.java", "androidx.paging.DataSource")
91    }
92
93    val POSITIONAL_DATA_SOURCE by lazy {
94        loadJavaCode("common/input/PositionalDataSource.java",
95                PagingTypeNames.POSITIONAL_DATA_SOURCE.toString())
96    }
97}
98fun testCodeGenScope(): CodeGenScope {
99    return CodeGenScope(Mockito.mock(ClassWriter::class.java))
100}
101
102fun simpleRun(vararg jfos: JavaFileObject, f: (TestInvocation) -> Unit): CompileTester {
103    return Truth.assertAbout(JavaSourcesSubjectFactory.javaSources())
104            .that(jfos.toList() + JavaFileObjects.forSourceString("foo.bar.MyClass",
105                    """
106                    package foo.bar;
107                    abstract public class MyClass {
108                    @androidx.room.Query("foo")
109                    abstract public void setFoo(String foo);
110                    }
111                    """))
112            .processedWith(TestProcessor.builder()
113                    .nextRunHandler {
114                        f(it)
115                        true
116                    }
117                    .forAnnotations(Query::class, PrimaryKey::class, Embedded::class,
118                            ColumnInfo::class, Relation::class, Entity::class)
119                    .build())
120}
121
122fun loadJavaCode(fileName: String, qName: String): JavaFileObject {
123    val contents = File("src/test/data/$fileName").readText(Charsets.UTF_8)
124    return JavaFileObjects.forSourceString(qName, contents)
125}
126
127fun createVerifierFromEntities(invocation: TestInvocation): DatabaseVerifier {
128    val entities = invocation.roundEnv.getElementsAnnotatedWith(Entity::class.java).map {
129        EntityProcessor(invocation.context, MoreElements.asType(it)).process()
130    }
131    return DatabaseVerifier.create(invocation.context, Mockito.mock(Element::class.java),
132            entities)!!
133}
134
135/**
136 * Create mocks of [Element] and [TypeMirror] so that they can be used for instantiating a fake
137 * [androidx.room.vo.Field].
138 */
139fun mockElementAndType(): Pair<Element, TypeMirror> {
140    val element = mock(Element::class.java)
141    val type = mock(TypeMirror::class.java)
142    doReturn(TypeKind.DECLARED).`when`(type).kind
143    doReturn(type).`when`(element).asType()
144    return element to type
145}
146