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