1 /* 2 * Copyright (C) 2019 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 android.processor.compat.unsupportedappusage; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import com.google.testing.compile.Compilation; 22 import com.google.testing.compile.CompilationSubject; 23 import com.google.testing.compile.Compiler; 24 import com.google.testing.compile.JavaFileObjects; 25 26 import org.junit.Test; 27 28 import java.io.IOException; 29 import java.util.List; 30 import java.util.Map; 31 import java.util.Optional; 32 import java.util.stream.Collectors; 33 34 import javax.tools.JavaFileObject; 35 import javax.tools.StandardLocation; 36 37 public class UnsupportedAppUsageProcessorTest { 38 39 private static final JavaFileObject ANNOTATION = JavaFileObjects.forSourceLines( 40 "android.compat.annotation.UnsupportedAppUsage", 41 "package android.compat.annotation;", 42 "public @interface UnsupportedAppUsage {", 43 " String expectedSignature() default \"\";\n", 44 " String someProperty() default \"\";", 45 " String overrideSourcePosition() default \"\";", 46 " String implicitMember() default \"\";", 47 "}"); 48 compile(JavaFileObject source)49 private Compilation compile(JavaFileObject source) { 50 Compilation compilation = 51 Compiler.javac().withProcessors(new UnsupportedAppUsageProcessor()) 52 .compile(ANNOTATION, source); 53 CompilationSubject.assertThat(compilation).succeeded(); 54 return compilation; 55 } 56 compileAndReadCsv(JavaFileObject source, String filename)57 private CsvReader compileAndReadCsv(JavaFileObject source, String filename) throws IOException { 58 Compilation compilation = compile(source); 59 Optional<JavaFileObject> csv = compilation.generatedFile( 60 StandardLocation.CLASS_OUTPUT, filename); 61 assertThat(csv.isPresent()).isTrue(); 62 63 return new CsvReader(csv.get().openInputStream()); 64 } 65 66 @Test testSignatureFormat()67 public void testSignatureFormat() throws Exception { 68 JavaFileObject src = JavaFileObjects.forSourceLines("a.b.Class", 69 "package a.b;", 70 "import android.compat.annotation.UnsupportedAppUsage;", 71 "public class Class {", 72 " @UnsupportedAppUsage", 73 " public void method() {}", 74 "}"); 75 assertThat(compileAndReadCsv(src, "a/b/Class.uau").getContents().get(0)).containsEntry( 76 "signature", "La/b/Class;->method()V" 77 ); 78 } 79 80 @Test testSourcePosition()81 public void testSourcePosition() throws Exception { 82 JavaFileObject src = JavaFileObjects.forSourceLines("a.b.Class", 83 "package a.b;", // 1 84 "import android.compat.annotation.UnsupportedAppUsage;", // 2 85 "public class Class {", // 3 86 " @UnsupportedAppUsage", // 4 87 " public void method() {}", // 5 88 "}"); 89 Map<String, String> row = compileAndReadCsv(src, "a/b/Class.uau").getContents().get(0); 90 assertThat(row).containsEntry("startline", "4"); 91 assertThat(row).containsEntry("startcol", "3"); 92 assertThat(row).containsEntry("endline", "4"); 93 assertThat(row).containsEntry("endcol", "23"); 94 } 95 96 @Test testAnnotationProperties()97 public void testAnnotationProperties() throws Exception { 98 JavaFileObject src = JavaFileObjects.forSourceLines("a.b.Class", 99 "package a.b;", // 1 100 "import android.compat.annotation.UnsupportedAppUsage;", // 2 101 "public class Class {", // 3 102 " @UnsupportedAppUsage(someProperty=\"value\")", // 4 103 " public void method() {}", // 5 104 "}"); 105 assertThat(compileAndReadCsv(src, "a/b/Class.uau").getContents().get(0)).containsEntry( 106 "properties", "someProperty=%22value%22"); 107 } 108 109 @Test testSourcePositionOverride()110 public void testSourcePositionOverride() throws Exception { 111 JavaFileObject src = JavaFileObjects.forSourceLines("a.b.Class", 112 "package a.b;", // 1 113 "import android.compat.annotation.UnsupportedAppUsage;", // 2 114 "public class Class {", // 3 115 " @UnsupportedAppUsage(overrideSourcePosition=\"otherfile.aidl:30:10:31:20\")", 116 " public void method() {}", // 5 117 "}"); 118 Map<String, String> row = compileAndReadCsv(src, "a/b/Class.uau").getContents().get(0); 119 assertThat(row).containsEntry("file", "otherfile.aidl"); 120 assertThat(row).containsEntry("startline", "30"); 121 assertThat(row).containsEntry("startcol", "10"); 122 assertThat(row).containsEntry("endline", "31"); 123 assertThat(row).containsEntry("endcol", "20"); 124 assertThat(row).containsEntry("properties", ""); 125 } 126 127 @Test testSourcePositionOverrideWrongFormat()128 public void testSourcePositionOverrideWrongFormat() throws Exception { 129 JavaFileObject src = JavaFileObjects.forSourceLines("a.b.Class", 130 "package a.b;", // 1 131 "import android.compat.annotation.UnsupportedAppUsage;", // 2 132 "public class Class {", // 3 133 " @UnsupportedAppUsage(overrideSourcePosition=\"invalid\")", // 4 134 " public void method() {}", // 5 135 "}"); 136 Compilation compilation = 137 Compiler.javac().withProcessors(new UnsupportedAppUsageProcessor()) 138 .compile(ANNOTATION, src); 139 CompilationSubject.assertThat(compilation).failed(); 140 CompilationSubject.assertThat(compilation).hadErrorContaining( 141 "Expected overrideSourcePosition to have format " 142 + "string:int:int:int:int").inFile(src).onLine(4); 143 } 144 145 @Test testSourcePositionOverrideInvalidInt()146 public void testSourcePositionOverrideInvalidInt() throws Exception { 147 JavaFileObject src = JavaFileObjects.forSourceLines("a.b.Class", 148 "package a.b;", // 1 149 "import android.compat.annotation.UnsupportedAppUsage;", // 2 150 "public class Class {", // 3 151 " @UnsupportedAppUsage(overrideSourcePosition=\"otherfile.aidl:a:b:c:d\")", // 4 152 " public void method() {}", // 5 153 "}"); 154 Compilation compilation = 155 Compiler.javac().withProcessors(new UnsupportedAppUsageProcessor()) 156 .compile(ANNOTATION, src); 157 CompilationSubject.assertThat(compilation).failed(); 158 CompilationSubject.assertThat(compilation).hadErrorContaining( 159 "Expected overrideSourcePosition to have format " 160 + "string:int:int:int:int").inFile(src).onLine(4); 161 } 162 163 @Test testImplicitMemberSkipped()164 public void testImplicitMemberSkipped() throws Exception { 165 JavaFileObject src = JavaFileObjects.forSourceLines("a.b.Class", 166 "package a.b;", // 1 167 "import android.compat.annotation.UnsupportedAppUsage;", // 2 168 "public class Class {", // 3 169 " @UnsupportedAppUsage(implicitMember=\"foo\")", // 4 170 " public void method() {}", // 5 171 "}"); 172 List<JavaFileObject> generatedNonClassFiles = 173 compile(src) 174 .generatedFiles() 175 .stream() 176 .filter(file -> !file.getName().endsWith(".class")) 177 .collect(Collectors.toList()); 178 assertThat(generatedNonClassFiles).hasSize(0); 179 } 180 181 @Test testExpectedSignatureSucceedsIfMatching()182 public void testExpectedSignatureSucceedsIfMatching() throws Exception { 183 JavaFileObject src = JavaFileObjects.forSourceLines("a.b.Class", 184 "package a.b;", // 1 185 "import android.compat.annotation.UnsupportedAppUsage;", // 2 186 "public class Class {", // 3 187 " @UnsupportedAppUsage(expectedSignature=\"La/b/Class;->method()V\")", // 4 188 " public void method() {}", // 5 189 "}"); 190 Compilation compilation = 191 Compiler.javac().withProcessors(new UnsupportedAppUsageProcessor()) 192 .compile(ANNOTATION, src); 193 CompilationSubject.assertThat(compilation).succeeded(); 194 } 195 196 @Test testExpectedSignatureThrowsErrorIfWrong()197 public void testExpectedSignatureThrowsErrorIfWrong() throws Exception { 198 JavaFileObject src = JavaFileObjects.forSourceLines("a.b.Class", 199 "package a.b;", // 1 200 "import android.compat.annotation.UnsupportedAppUsage;", // 2 201 "public class Class {", // 3 202 " @UnsupportedAppUsage(expectedSignature=\"expected\")", // 4 203 " public void method() {}", // 5 204 "}"); 205 Compilation compilation = 206 Compiler.javac().withProcessors(new UnsupportedAppUsageProcessor()) 207 .compile(ANNOTATION, src); 208 CompilationSubject.assertThat(compilation).failed(); 209 CompilationSubject.assertThat(compilation).hadErrorContaining( 210 "Expected signature doesn't match generated signature").inFile(src).onLine(5); 211 } 212 213 } 214