1 /*
2  * Copyright (C) 2018 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.class2greylist;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.mockito.ArgumentMatchers.any;
22 import static org.mockito.ArgumentMatchers.eq;
23 import static org.mockito.Mockito.atLeastOnce;
24 import static org.mockito.Mockito.times;
25 import static org.mockito.Mockito.verify;
26 
27 import static java.util.Collections.emptySet;
28 
29 import com.google.common.base.Joiner;
30 import com.google.common.collect.ImmutableMap;
31 import com.google.common.collect.ImmutableSet;
32 
33 import org.junit.Before;
34 import org.junit.Test;
35 import org.mockito.ArgumentCaptor;
36 
37 import java.io.IOException;
38 import java.util.Map;
39 
40 public class CovariantReturnTypeHandlerTest extends AnnotationHandlerTestBase {
41 
42     private static final String ANNOTATION = "Lannotation/Annotation;";
43     private static final String FLAG = "test-flag";
44 
45     @Before
setup()46     public void setup() throws IOException {
47         // To keep the test simpler and more concise, we don't use the real
48         // @CovariantReturnType annotation here, but use our own @Annotation.
49         // It doesn't have to match the real annotation, just have the same
50         // property (returnType).
51         mJavac.addSource("annotation.Annotation", Joiner.on('\n').join(
52                 "package annotation;",
53                 "import static java.lang.annotation.RetentionPolicy.CLASS;",
54                 "import java.lang.annotation.Retention;",
55                 "@Retention(CLASS)",
56                 "public @interface Annotation {",
57                 "  Class<?> returnType();",
58                 "}"));
59     }
60 
61     @Test
testReturnTypeWhitelisted()62     public void testReturnTypeWhitelisted() throws IOException {
63         mJavac.addSource("a.b.Class", Joiner.on('\n').join(
64                 "package a.b;",
65                 "import annotation.Annotation;",
66                 "public class Class {",
67                 "  @Annotation(returnType=Integer.class)",
68                 "  public String method() {return null;}",
69                 "}"));
70         mJavac.compile();
71 
72         Map<String, AnnotationHandler> handlerMap =
73                 ImmutableMap.of(ANNOTATION,
74                         new CovariantReturnTypeHandler(
75                                 mConsumer,
76                                 ImmutableSet.of("La/b/Class;->method()Ljava/lang/String;"),
77                                 FLAG));
78         new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit();
79 
80         assertNoErrors();
81         verify(mConsumer, times(1)).consume(
82                 eq("La/b/Class;->method()Ljava/lang/Integer;"), any(), eq(ImmutableSet.of(FLAG)));
83     }
84 
85     @Test
testAnnotatedMemberNotPublicApi()86     public void testAnnotatedMemberNotPublicApi() throws IOException {
87         mJavac.addSource("a.b.Class", Joiner.on('\n').join(
88                 "package a.b;",
89                 "import annotation.Annotation;",
90                 "public class Class {",
91                 "  @Annotation(returnType=Integer.class)",
92                 "  public String method() {return null;}",
93                 "}"));
94         mJavac.compile();
95 
96         Map<String, AnnotationHandler> handlerMap =
97                 ImmutableMap.of(ANNOTATION,
98                         new CovariantReturnTypeHandler(
99                                 mConsumer,
100                                 emptySet(),
101                                 FLAG));
102         new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit();
103 
104         verify(mStatus, atLeastOnce()).error(any(), any());
105     }
106 
107     @Test
testReturnTypeAlreadyWhitelisted()108     public void testReturnTypeAlreadyWhitelisted() throws IOException {
109         mJavac.addSource("a.b.Class", Joiner.on('\n').join(
110                 "package a.b;",
111                 "import annotation.Annotation;",
112                 "public class Class {",
113                 "  @Annotation(returnType=Integer.class)",
114                 "  public String method() {return null;}",
115                 "}"));
116         mJavac.compile();
117 
118         Map<String, AnnotationHandler> handlerMap =
119                 ImmutableMap.of(ANNOTATION,
120                         new CovariantReturnTypeHandler(
121                                 mConsumer,
122                                 ImmutableSet.of(
123                                         "La/b/Class;->method()Ljava/lang/String;",
124                                         "La/b/Class;->method()Ljava/lang/Integer;"
125                                 ),
126                                 FLAG));
127         new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit();
128 
129         verify(mStatus, atLeastOnce()).error(any(), any());
130     }
131 
132     @Test
testAnnotationOnField()133     public void testAnnotationOnField() throws IOException {
134         mJavac.addSource("a.b.Class", Joiner.on('\n').join(
135                 "package a.b;",
136                 "import annotation.Annotation;",
137                 "public class Class {",
138                 "  @Annotation(returnType=Integer.class)",
139                 "  public String field;",
140                 "}"));
141         mJavac.compile();
142 
143         Map<String, AnnotationHandler> handlerMap =
144                 ImmutableMap.of(ANNOTATION,
145                         new CovariantReturnTypeHandler(
146                                 mConsumer,
147                                 emptySet(),
148                                 FLAG));
149         new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), mStatus, handlerMap).visit();
150 
151         verify(mStatus, atLeastOnce()).error(any(), any());
152     }
153 }
154