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