• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 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.binder.bytecode;
18 
19 import static com.google.common.collect.Iterables.getLast;
20 import static com.google.common.collect.MoreCollectors.onlyElement;
21 import static com.google.common.truth.Truth.assertThat;
22 import static com.google.turbine.testing.TestClassPaths.TURBINE_BOOTCLASSPATH;
23 import static java.util.Objects.requireNonNull;
24 
25 import com.google.common.collect.ImmutableMap;
26 import com.google.common.io.ByteStreams;
27 import com.google.turbine.binder.bound.TurbineClassValue;
28 import com.google.turbine.binder.bound.TypeBoundClass;
29 import com.google.turbine.binder.bound.TypeBoundClass.MethodInfo;
30 import com.google.turbine.binder.env.CompoundEnv;
31 import com.google.turbine.binder.env.Env;
32 import com.google.turbine.binder.env.SimpleEnv;
33 import com.google.turbine.binder.sym.ClassSymbol;
34 import com.google.turbine.type.Type;
35 import com.google.turbine.type.Type.ClassTy;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.io.Serializable;
39 import java.io.UncheckedIOException;
40 import java.util.List;
41 import org.junit.Test;
42 import org.junit.runner.RunWith;
43 import org.junit.runners.JUnit4;
44 
45 @RunWith(JUnit4.class)
46 public class BytecodeBoundClassTest {
47 
48   static class NoInterfaces {}
49 
50   abstract static class RawInterfaces implements Serializable {}
51 
52   abstract static class GenericInterfaces implements List<String> {}
53 
54   @Test
interfaceTypes()55   public void interfaceTypes() {
56     TypeBoundClass noInterfaces = getBytecodeBoundClass(NoInterfaces.class);
57     TypeBoundClass rawInterfaces = getBytecodeBoundClass(RawInterfaces.class);
58     TypeBoundClass genericInterfaces = getBytecodeBoundClass(GenericInterfaces.class);
59 
60     assertThat(noInterfaces.interfaceTypes()).isEmpty();
61 
62     assertThat(rawInterfaces.interfaceTypes()).hasSize(1);
63     assertThat(((ClassTy) rawInterfaces.interfaceTypes().get(0)).sym())
64         .isEqualTo(new ClassSymbol("java/io/Serializable"));
65     assertThat(getLast(((ClassTy) rawInterfaces.interfaceTypes().get(0)).classes()).targs())
66         .isEmpty();
67 
68     assertThat(genericInterfaces.interfaceTypes()).hasSize(1);
69     assertThat(((ClassTy) genericInterfaces.interfaceTypes().get(0)).sym())
70         .isEqualTo(new ClassSymbol("java/util/List"));
71     assertThat(getLast(((ClassTy) genericInterfaces.interfaceTypes().get(0)).classes()).targs())
72         .hasSize(1);
73     assertThat(
74             ((ClassTy)
75                     getLast(((ClassTy) genericInterfaces.interfaceTypes().get(0)).classes())
76                         .targs()
77                         .get(0))
78                 .sym())
79         .isEqualTo(new ClassSymbol("java/lang/String"));
80   }
81 
82   static class HasMethod {
83     @Deprecated
foo(@eprecated X bar, Y baz)84     <X, Y extends X, Z extends Throwable> X foo(@Deprecated X bar, Y baz) throws IOException, Z {
85       return null;
86     }
87   }
88 
89   @Test
methodTypes()90   public void methodTypes() {
91     MethodInfo m =
92         getBytecodeBoundClass(HasMethod.class).methods().stream()
93             .filter(x -> x.name().equals("foo"))
94             .collect(onlyElement());
95 
96     assertThat(m.tyParams()).hasSize(3);
97     assertThat(m.parameters().get(0).annotations()).hasSize(1);
98     assertThat(m.parameters().get(0).name()).isEqualTo("bar");
99     assertThat(m.exceptions()).hasSize(2);
100   }
101 
102   @interface VoidAnno {
a()103     Class<?> a() default void.class;
104 
b()105     Class<?> b() default int[].class;
106   }
107 
108   @Test
voidAnno()109   public void voidAnno() {
110     BytecodeBoundClass c = getBytecodeBoundClass(VoidAnno.class);
111 
112     assertThat(c.methods()).hasSize(2);
113     assertThat(((TurbineClassValue) c.methods().get(0).defaultValue()).type().tyKind())
114         .isEqualTo(Type.TyKind.VOID_TY);
115     assertThat(((TurbineClassValue) c.methods().get(1).defaultValue()).type().tyKind())
116         .isEqualTo(Type.TyKind.ARRAY_TY);
117   }
118 
toByteArrayOrDie(InputStream is)119   private static byte[] toByteArrayOrDie(InputStream is) {
120     try {
121       return ByteStreams.toByteArray(is);
122     } catch (IOException e) {
123       throw new UncheckedIOException(e);
124     }
125   }
126 
getBytecodeBoundClass( Env<ClassSymbol, BytecodeBoundClass> env, Class<?> clazz)127   private BytecodeBoundClass getBytecodeBoundClass(
128       Env<ClassSymbol, BytecodeBoundClass> env, Class<?> clazz) {
129     String name = clazz.getName().replace('.', '/');
130     String path = "/" + name + ".class";
131     return new BytecodeBoundClass(
132         new ClassSymbol(name),
133         () -> toByteArrayOrDie(requireNonNull(getClass().getResourceAsStream(path), path)),
134         env,
135         "test.jar");
136   }
137 
getBytecodeBoundClass(Class<?> clazz)138   private BytecodeBoundClass getBytecodeBoundClass(Class<?> clazz) {
139     Env<ClassSymbol, BytecodeBoundClass> env = TURBINE_BOOTCLASSPATH.env();
140     env =
141         CompoundEnv.of(env)
142             .append(
143                 new SimpleEnv<>(
144                     ImmutableMap.of(
145                         new ClassSymbol(BytecodeBoundClass.class.getName().replace('.', '/')),
146                         getBytecodeBoundClass(env, BytecodeBoundClassTest.class))));
147     return getBytecodeBoundClass(env, clazz);
148   }
149 }
150