1/* 2 * Copyright 2017 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 17package androidx.room.solver 18 19import androidx.room.ext.getAllFieldsIncludingPrivateSupers 20import androidx.room.ext.isAssignableWithoutVariance 21import androidx.room.testing.TestInvocation 22import com.google.testing.compile.JavaFileObjects 23import org.hamcrest.CoreMatchers.`is` 24import org.hamcrest.MatcherAssert.assertThat 25import org.junit.Test 26import simpleRun 27import javax.annotation.processing.ProcessingEnvironment 28import javax.lang.model.element.TypeElement 29import javax.lang.model.element.VariableElement 30 31class TypeAssignmentTest { 32 companion object { 33 private val TEST_OBJECT = JavaFileObjects.forSourceString("foo.bar.MyObject", 34 """ 35 package foo.bar; 36 import java.util.Set; 37 import java.util.HashSet; 38 import java.util.Map; 39 class MyObject { 40 String mString; 41 Integer mInteger; 42 Set<MyObject> mSet; 43 Set<? extends MyObject> mVarianceSet; 44 HashSet<MyObject> mHashSet; 45 Map<String, ?> mUnboundedMap; 46 Map<String, String> mStringMap; 47 } 48 """.trimIndent()) 49 } 50 51 @Test 52 fun basic() { 53 runTest { 54 val testObject = typeElement("foo.bar.MyObject") 55 val string = testObject.getField(processingEnv, "mString") 56 val integer = testObject.getField(processingEnv, "mInteger") 57 assertThat(typeUtils.isAssignableWithoutVariance(string.asType(), 58 integer.asType()), 59 `is`(false)) 60 } 61 } 62 63 @Test 64 fun generics() { 65 runTest { 66 val testObject = typeElement("foo.bar.MyObject") 67 val set = testObject.getField(processingEnv, "mSet").asType() 68 val hashSet = testObject.getField(processingEnv, "mHashSet").asType() 69 assertThat(typeUtils.isAssignableWithoutVariance( 70 from = set, 71 to = hashSet 72 ), `is`(false)) 73 assertThat(typeUtils.isAssignableWithoutVariance( 74 from = hashSet, 75 to = set 76 ), `is`(true)) 77 } 78 } 79 80 @Test 81 fun variance() { 82 /** 83 * Set<User> userSet = null; 84 * Set<? extends User> userSet2 = null; 85 * userSet = userSet2; // NOT OK for java but kotlin data classes hit this so we want 86 * // to accept it 87 */ 88 runTest { 89 val testObject = typeElement("foo.bar.MyObject") 90 val set = testObject.getField(processingEnv, "mSet").asType() 91 val varianceSet = testObject.getField(processingEnv, "mVarianceSet").asType() 92 assertThat(typeUtils.isAssignableWithoutVariance( 93 from = set, 94 to = varianceSet 95 ), `is`(true)) 96 assertThat(typeUtils.isAssignableWithoutVariance( 97 from = varianceSet, 98 to = set 99 ), `is`(true)) 100 } 101 } 102 103 @Test 104 fun unboundedVariance() { 105 runTest { 106 val testObject = typeElement("foo.bar.MyObject") 107 val unbounded = testObject.getField(processingEnv, "mUnboundedMap").asType() 108 val objectMap = testObject.getField(processingEnv, "mStringMap").asType() 109 assertThat(typeUtils.isAssignableWithoutVariance( 110 from = unbounded, 111 to = objectMap 112 ), `is`(false)) 113 assertThat(typeUtils.isAssignableWithoutVariance( 114 from = objectMap, 115 to = unbounded 116 ), `is`(true)) 117 } 118 } 119 120 private fun TypeElement.getField( 121 env: ProcessingEnvironment, 122 name: String): VariableElement { 123 return getAllFieldsIncludingPrivateSupers(env).first { 124 it.simpleName.toString() == name 125 } 126 } 127 128 private fun runTest(handler: TestInvocation.() -> Unit) { 129 simpleRun(TEST_OBJECT) { 130 it.apply { handler() } 131 }.compilesWithoutError() 132 } 133}