1 /*
2  * Copyright (C) 2024 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 
17 package com.android.tools.metalava.model.testsuite.typeitem
18 
19 import com.android.tools.metalava.model.testsuite.BaseModelTest
20 import com.android.tools.metalava.testing.java
21 import com.android.tools.metalava.testing.kotlin
22 import com.google.common.truth.Truth.assertThat
23 import org.junit.Test
24 import org.junit.runners.Parameterized
25 
26 class CommonIsAssignableFromTest : BaseModelTest() {
27 
28     data class Comparison(
29         val field1: String,
30         val field2: String,
31         val expectedResult: Boolean,
32     ) {
toStringnull33         override fun toString(): String {
34             return "$field1 to $field2"
35         }
36     }
37 
38     companion object {
39         private val comparisons =
40             listOf(
41                 Comparison("string", "string", true),
42                 Comparison("obj", "string", true),
43                 Comparison("string", "obj", false),
44                 Comparison("primitiveInt", "number", false),
45                 Comparison("number", "primitiveInt", true),
46                 Comparison("boxedInt", "primitiveInt", true),
47                 Comparison("primitiveInt", "boxedInt", false),
48                 Comparison("number", "boxedInt", true),
49                 Comparison("boxedInt", "number", false),
50                 Comparison("listOfInt", "listOfInt", true),
51                 Comparison("listOfInt", "listOfNumber", false),
52                 Comparison("listOfNumber", "listOfInt", false),
53                 Comparison("mapOfNumberToString", "mapOfNumberToString", true),
54                 Comparison("mapOfNumberToString", "mapOfIntToString", false),
55                 Comparison("mapOfIntToString", "mapOfNumberToString", false),
56             )
57 
comparisonsnull58         @JvmStatic @Parameterized.Parameters fun comparisons() = comparisons
59     }
60 
61     /**
62      * Set by injection by [Parameterized] after class initializers are called.
63      *
64      * Anything that accesses this, either directly or indirectly must do it after initialization,
65      * e.g. from lazy fields or in methods called from test methods.
66      *
67      * See [codebaseCreatorConfig] for more info.
68      */
69     @Parameterized.Parameter(0) lateinit var comparison: Comparison
70 
71     @Test
72     fun `Test assignability without unboxing`() {
73 
74         runCodebaseTest(
75             java(
76                 """
77                 package test.foo;
78                 import java.util.*;
79                 public class Subject {
80                     public Object obj;
81                     public String string;
82                     public int primitiveInt;
83                     public Number number;
84                     public Integer boxedInt;
85                     public List<Integer> listOfInt;
86                     public List<Number> listOfNumber;
87                     public Map<Integer, String> mapOfIntToString;
88                     public Map<Number, String> mapOfNumberToString;
89                 }
90                 """
91             ),
92             kotlin(
93                 """
94                 package test.foo
95                 class Subject {
96                     @JvmField
97                     var obj: Any? = null
98                     @JvmField
99                     var string: String? = null
100                     @JvmField
101                     var primitiveInt = 0
102                     @JvmField
103                     var number: Number? = null
104                     @JvmField
105                     var boxedInt: Int? = null
106                     @JvmField
107                     var listOfInt: MutableList<Int>? = null
108                     @JvmField
109                     var listOfNumber: MutableList<Number>? = null
110                     @JvmField
111                     var mapOfIntToString: MutableMap<Int, String>? = null
112                     @JvmField
113                     var mapOfNumberToString: MutableMap<Number, String>? = null
114                 }
115                 """
116             ),
117             signature(
118                 """
119                     // Signature format: 3.0
120                     package test.foo {
121                       public class Subject {
122                         field public Object obj;
123                         field public String string;
124                         field public int primitiveInt;
125                         field public Number number;
126                         field public Integer boxedInt;
127                         field public java.util.List<Integer> listOfInt;
128                         field public java.util.List<Number> listOfNumber;
129                         field public java.util.Map<Integer, String> mapOfIntToString;
130                         field public java.util.Map<Number, String> mapOfNumberToString;
131                       }
132                     }
133                 """
134             ),
135         ) {
136             val subject = codebase.assertClass("test.foo.Subject")
137 
138             val field1Type = subject.assertField(comparison.field1).type()
139             val field2Type = subject.assertField(comparison.field2).type()
140 
141             assertThat(field1Type.isAssignableFromWithoutUnboxing(field2Type))
142                 .isEqualTo(comparison.expectedResult)
143         }
144     }
145 }
146