1 /* 2 * Copyright 2019 Google Inc. All Rights Reserved. 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.google.turbine.processing; 18 19 import static com.google.common.collect.ImmutableList.toImmutableList; 20 import static com.google.common.truth.Truth.assertThat; 21 import static java.util.Objects.requireNonNull; 22 23 import com.google.common.base.Joiner; 24 import com.google.common.collect.ImmutableList; 25 import com.google.turbine.binder.Binder; 26 import com.google.turbine.binder.ClassPathBinder; 27 import com.google.turbine.binder.bound.TypeBoundClass; 28 import com.google.turbine.binder.env.CompoundEnv; 29 import com.google.turbine.binder.env.Env; 30 import com.google.turbine.binder.env.SimpleEnv; 31 import com.google.turbine.binder.sym.ClassSymbol; 32 import com.google.turbine.diag.SourceFile; 33 import com.google.turbine.lower.IntegrationTestSupport; 34 import com.google.turbine.lower.IntegrationTestSupport.TestInput; 35 import com.google.turbine.parse.Parser; 36 import com.google.turbine.testing.TestClassPaths; 37 import com.google.turbine.tree.Tree.CompUnit; 38 import com.sun.source.util.JavacTask; 39 import java.util.Arrays; 40 import java.util.Collection; 41 import java.util.List; 42 import java.util.Optional; 43 import javax.lang.model.element.Element; 44 import javax.lang.model.util.Elements; 45 import org.junit.Test; 46 import org.junit.runner.RunWith; 47 import org.junit.runners.Parameterized; 48 import org.junit.runners.Parameterized.Parameters; 49 50 @RunWith(Parameterized.class) 51 public class TurbineElementsGetAllMembersTest { 52 53 @Parameters parameters()54 public static Iterable<Object[]> parameters() { 55 // An array of test inputs. Each element is an array of lines of sources to compile. 56 String[][] inputs = { 57 { 58 "=== Test.java ===", // 59 "class Test {", 60 "}", 61 }, 62 { 63 "=== A.java ===", 64 "interface A {", 65 " Integer f();", 66 "}", 67 "=== B.java ===", 68 "interface B {", 69 " Integer f();", 70 "}", 71 "=== Test.java ===", // 72 "class Test implements A, B {", 73 " Integer f() {", 74 " return 42;", 75 " }", 76 "}", 77 }, 78 { 79 "=== I.java ===", 80 "abstract class I {", 81 " abstract Integer f();", 82 "}", 83 "=== J.java ===", 84 "interface J extends I {", 85 " default Integer f() {", 86 " return 42;", 87 " }", 88 "}", 89 "=== Test.java ===", // 90 "class Test extends I implements J {", 91 "}", 92 }, 93 { 94 "=== I.java ===", 95 "interface I {", 96 " Integer f();", 97 "}", 98 "=== J.java ===", 99 "interface J extends I {", 100 " default Integer f() {", 101 " return 42;", 102 " }", 103 "}", 104 "=== Test.java ===", // 105 "class Test implements J, I {", 106 "}", 107 }, 108 { 109 "=== p/A.java ===", 110 "package p;", 111 "public class A {", 112 " public boolean f() {", 113 " return true;", 114 " }", 115 "}", 116 "=== p/B.java ===", 117 "package p;", 118 "public interface B {", 119 " public boolean f();", 120 "}", 121 "=== Test.java ===", // 122 "import p.*;", 123 "class Test extends A implements B {", 124 "}", 125 }, 126 { 127 "=== p/A.java ===", 128 "package p;", 129 "public class A {", 130 " public boolean f() {", 131 " return true;", 132 " }", 133 "}", 134 "=== p/B.java ===", 135 "package p;", 136 "public interface B {", 137 " public boolean f();", 138 "}", 139 "=== Middle.java ===", // 140 "import p.*;", 141 "public abstract class Middle extends A implements B {", 142 "}", 143 "=== Test.java ===", // 144 "class Test extends Middle {", 145 "}", 146 }, 147 { 148 "=== A.java ===", 149 "interface A {", 150 " Integer f();", 151 "}", 152 "=== B.java ===", 153 "interface B {", 154 " Number f();", 155 "}", 156 "=== Test.java ===", // 157 "abstract class Test implements A, B {", 158 "}", 159 }, 160 { 161 "=== A.java ===", 162 "interface A {", 163 " Integer f();", 164 "}", 165 "=== B.java ===", 166 "interface B {", 167 " Integer f();", 168 "}", 169 "=== Test.java ===", // 170 "abstract class Test implements A, B {", 171 "}", 172 }, 173 { 174 "=== I.java ===", 175 "interface I {", 176 " int x;", 177 "}", 178 "=== J.java ===", 179 "interface J {", 180 " int x;", 181 "}", 182 "=== B.java ===", 183 "class B {", 184 " int x;", 185 "}", 186 "=== C.java ===", 187 "class C extends B {", 188 " static int x;", 189 "}", 190 "=== Test.java ===", 191 "class Test extends C implements I, J {", 192 " int x;", 193 "}", 194 }, 195 { 196 "=== one/A.java ===", 197 "public class A {", 198 " int a;", 199 "}", 200 "=== two/B.java ===", 201 "public class B extends A {", 202 " int b;", 203 " private int c;", 204 " protected int d;", 205 "}", 206 "=== Test.java ===", 207 "public class Test extends B {", 208 " int x;", 209 "}", 210 }, 211 { 212 "=== A.java ===", 213 "interface A {", 214 " class I {}", 215 "}", 216 "=== B.java ===", 217 "interface B {", 218 " class J {}", 219 "}", 220 "=== Test.java ===", // 221 "abstract class Test implements A, B {", 222 "}", 223 }, 224 { 225 "=== A.java ===", 226 "import java.util.List;", 227 "interface A<T> {", 228 " List<? extends T> f();", 229 "}", 230 "=== Test.java ===", 231 "import java.util.List;", 232 "class Test<T extends Number> implements A<T> {", 233 " public List<? extends T> f() {", 234 " return null;", 235 " }", 236 "}", 237 }, 238 }; 239 return Arrays.stream(inputs) 240 .map(input -> TestInput.parse(Joiner.on('\n').join(input))) 241 .map(x -> new Object[] {x}) 242 .collect(toImmutableList()); 243 } 244 245 private final TestInput input; 246 TurbineElementsGetAllMembersTest(TestInput input)247 public TurbineElementsGetAllMembersTest(TestInput input) { 248 this.input = input; 249 } 250 251 // Compile the test inputs with javac and turbine, and assert that getAllMembers returns the 252 // same elements under each implementation. 253 @Test test()254 public void test() throws Exception { 255 JavacTask javacTask = 256 IntegrationTestSupport.runJavacAnalysis( 257 input.sources, ImmutableList.of(), ImmutableList.of()); 258 Elements javacElements = javacTask.getElements(); 259 List<? extends Element> javacMembers = 260 javacElements.getAllMembers(requireNonNull(javacElements.getTypeElement("Test"))); 261 262 ImmutableList<CompUnit> units = 263 input.sources.entrySet().stream() 264 .map(e -> new SourceFile(e.getKey(), e.getValue())) 265 .map(Parser::parse) 266 .collect(toImmutableList()); 267 268 Binder.BindingResult bound = 269 Binder.bind( 270 units, 271 ClassPathBinder.bindClasspath(ImmutableList.of()), 272 TestClassPaths.TURBINE_BOOTCLASSPATH, 273 Optional.empty()); 274 275 Env<ClassSymbol, TypeBoundClass> env = 276 CompoundEnv.<ClassSymbol, TypeBoundClass>of(bound.classPathEnv()) 277 .append(new SimpleEnv<>(bound.units())); 278 ModelFactory factory = new ModelFactory(env, ClassLoader.getSystemClassLoader(), bound.tli()); 279 TurbineTypes turbineTypes = new TurbineTypes(factory); 280 TurbineElements turbineElements = new TurbineElements(factory, turbineTypes); 281 List<? extends Element> turbineMembers = 282 turbineElements.getAllMembers(factory.typeElement(new ClassSymbol("Test"))); 283 284 assertThat(formatElements(turbineMembers)) 285 .containsExactlyElementsIn(formatElements(javacMembers)); 286 } 287 formatElements(Collection<? extends Element> elements)288 private static ImmutableList<String> formatElements(Collection<? extends Element> elements) { 289 return elements.stream() 290 .map(e -> String.format("%s %s.%s %s", e.getKind(), e.getEnclosingElement(), e, e.asType())) 291 .collect(toImmutableList()); 292 } 293 } 294