Home | History | Annotate | Download | only in bytecode
      1 /*
      2  * Copyright 2016 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.bytecode;
     18 
     19 import static com.google.common.truth.Truth.assertThat;
     20 
     21 import com.google.common.base.Strings;
     22 import com.google.common.collect.Iterables;
     23 import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue;
     24 import com.google.turbine.model.Const;
     25 import com.google.turbine.model.TurbineConstantTypeKind;
     26 import com.google.turbine.model.TurbineFlag;
     27 import org.junit.Test;
     28 import org.junit.runner.RunWith;
     29 import org.junit.runners.JUnit4;
     30 import org.objectweb.asm.AnnotationVisitor;
     31 import org.objectweb.asm.ClassWriter;
     32 import org.objectweb.asm.Opcodes;
     33 
     34 @RunWith(JUnit4.class)
     35 public class ClassReaderTest {
     36 
     37   @Test
     38   public void methods() {
     39     ClassWriter cw = new ClassWriter(0);
     40     cw.visitAnnotation("Ljava/lang/Deprecated;", true);
     41     cw.visit(
     42         52,
     43         Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_SUPER,
     44         "test/Hello",
     45         null,
     46         "java/lang/Object",
     47         null);
     48     cw.visitMethod(
     49         Opcodes.ACC_PUBLIC,
     50         "f",
     51         "(Ljava/lang/String;)Ljava/lang/String;",
     52         "<T:Ljava/lang/String;>(TT;)TT;",
     53         null);
     54     cw.visitMethod(
     55         Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
     56         "g",
     57         "(Z)V",
     58         "<T:Ljava/lang/Error;>(Z)V^TT;",
     59         new String[] {"java/lang/Error"});
     60     cw.visitMethod(0, "h", "(I)V", null, null);
     61     byte[] bytes = cw.toByteArray();
     62 
     63     ClassFile classFile = com.google.turbine.bytecode.ClassReader.read(null, bytes);
     64 
     65     assertThat(classFile.access())
     66         .isEqualTo(TurbineFlag.ACC_PUBLIC | TurbineFlag.ACC_FINAL | TurbineFlag.ACC_SUPER);
     67     assertThat(classFile.name()).isEqualTo("test/Hello");
     68     assertThat(classFile.signature()).isNull();
     69     assertThat(classFile.superName()).isEqualTo("java/lang/Object");
     70     assertThat(classFile.interfaces()).isEmpty();
     71 
     72     assertThat(classFile.methods()).hasSize(3);
     73 
     74     ClassFile.MethodInfo f = classFile.methods().get(0);
     75     assertThat(f.access()).isEqualTo(TurbineFlag.ACC_PUBLIC);
     76     assertThat(f.name()).isEqualTo("f");
     77     assertThat(f.descriptor()).isEqualTo("(Ljava/lang/String;)Ljava/lang/String;");
     78     assertThat(f.signature()).isEqualTo("<T:Ljava/lang/String;>(TT;)TT;");
     79     assertThat(f.exceptions()).isEmpty();
     80     assertThat(f.annotations()).isEmpty();
     81     assertThat(f.parameterAnnotations()).isEmpty();
     82     assertThat(f.defaultValue()).isNull();
     83 
     84     ClassFile.MethodInfo g = classFile.methods().get(1);
     85     assertThat(g.access()).isEqualTo(TurbineFlag.ACC_PUBLIC | TurbineFlag.ACC_STATIC);
     86     assertThat(g.name()).isEqualTo("g");
     87     assertThat(g.descriptor()).isEqualTo("(Z)V");
     88     assertThat(g.signature()).isEqualTo("<T:Ljava/lang/Error;>(Z)V^TT;");
     89 
     90     ClassFile.MethodInfo h = classFile.methods().get(2);
     91     assertThat(h.access()).isEqualTo(0);
     92     assertThat(h.name()).isEqualTo("h");
     93     assertThat(h.descriptor()).isEqualTo("(I)V");
     94     assertThat(h.signature()).isNull();
     95   }
     96 
     97   @Test
     98   public void annotationDeclaration() {
     99     ClassWriter cw = new ClassWriter(0);
    100     cw.visit(
    101         52,
    102         Opcodes.ACC_PUBLIC + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ABSTRACT + Opcodes.ACC_INTERFACE,
    103         "test/Hello",
    104         null,
    105         "java/lang/Object",
    106         new String[] {"java/lang/annotation/Annotation"});
    107     AnnotationVisitor av = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
    108     av.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;", "RUNTIME");
    109     av.visitEnd();
    110     cw.visitEnd();
    111     byte[] bytes = cw.toByteArray();
    112 
    113     ClassFile classFile = com.google.turbine.bytecode.ClassReader.read(null, bytes);
    114 
    115     assertThat(classFile.access())
    116         .isEqualTo(
    117             TurbineFlag.ACC_PUBLIC
    118                 | TurbineFlag.ACC_ANNOTATION
    119                 | TurbineFlag.ACC_ABSTRACT
    120                 | TurbineFlag.ACC_INTERFACE);
    121     assertThat(classFile.name()).isEqualTo("test/Hello");
    122     assertThat(classFile.signature()).isNull();
    123     assertThat(classFile.superName()).isEqualTo("java/lang/Object");
    124     assertThat(classFile.interfaces()).containsExactly("java/lang/annotation/Annotation");
    125 
    126     assertThat(classFile.annotations()).hasSize(1);
    127     ClassFile.AnnotationInfo annotation = Iterables.getOnlyElement(classFile.annotations());
    128     assertThat(annotation.typeName()).isEqualTo("Ljava/lang/annotation/Retention;");
    129     assertThat(annotation.isRuntimeVisible()).isTrue();
    130     assertThat(annotation.elementValuePairs()).hasSize(1);
    131     assertThat(annotation.elementValuePairs()).containsKey("value");
    132     ElementValue value = annotation.elementValuePairs().get("value");
    133     assertThat(value.kind()).isEqualTo(ElementValue.Kind.ENUM);
    134     ElementValue.EnumConstValue enumValue = (ElementValue.EnumConstValue) value;
    135     assertThat(enumValue.typeName()).isEqualTo("Ljava/lang/annotation/RetentionPolicy;");
    136     assertThat(enumValue.constName()).isEqualTo("RUNTIME");
    137   }
    138 
    139   @Test
    140   public void fields() {
    141     ClassWriter cw = new ClassWriter(0);
    142     cw.visit(
    143         52,
    144         Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER,
    145         "test/Hello",
    146         "<X:Ljava/lang/Object;>Ljava/lang/Object;",
    147         "java/lang/Object",
    148         null);
    149     cw.visitField(Opcodes.ACC_PUBLIC, "x", "I", null, null);
    150     cw.visitField(
    151         Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_STATIC,
    152         "y",
    153         "I",
    154         null,
    155         Integer.valueOf(42));
    156     cw.visitField(Opcodes.ACC_PUBLIC, "z", "Ljava/util/List;", "Ljava/util/List<TX;>;", null);
    157     cw.visitEnd();
    158     byte[] bytes = cw.toByteArray();
    159 
    160     ClassFile classFile = com.google.turbine.bytecode.ClassReader.read(null, bytes);
    161 
    162     assertThat(classFile.fields()).hasSize(3);
    163 
    164     ClassFile.FieldInfo x = classFile.fields().get(0);
    165     assertThat(x.access()).isEqualTo(TurbineFlag.ACC_PUBLIC);
    166     assertThat(x.name()).isEqualTo("x");
    167     assertThat(x.descriptor()).isEqualTo("I");
    168     assertThat(x.signature()).isNull();
    169     assertThat(x.value()).isNull();
    170     assertThat(x.annotations()).isEmpty();
    171 
    172     ClassFile.FieldInfo y = classFile.fields().get(1);
    173     assertThat(y.access())
    174         .isEqualTo(TurbineFlag.ACC_PUBLIC | TurbineFlag.ACC_STATIC | TurbineFlag.ACC_FINAL);
    175     assertThat(y.name()).isEqualTo("y");
    176     assertThat(y.descriptor()).isEqualTo("I");
    177     assertThat(y.value().constantTypeKind()).isEqualTo(TurbineConstantTypeKind.INT);
    178     assertThat(((Const.IntValue) y.value()).value()).isEqualTo(42);
    179 
    180     ClassFile.FieldInfo z = classFile.fields().get(2);
    181     assertThat(z.name()).isEqualTo("z");
    182     assertThat(z.descriptor()).isEqualTo("Ljava/util/List;");
    183     // don't bother reading signatures for fields; we only care about constants
    184     assertThat(z.signature()).isNull();
    185   }
    186 
    187   @Test
    188   public void innerClass() {
    189     ClassWriter cw = new ClassWriter(0);
    190     cw.visit(52, Opcodes.ACC_SUPER, "test/Hello$Inner", null, "java/lang/Object", null);
    191     cw.visitInnerClass(
    192         "test/Hello$Inner", "test/Hello", "Inner", Opcodes.ACC_STATIC | Opcodes.ACC_PRIVATE);
    193     cw.visitInnerClass("test/Hello$Inner$InnerMost", "test/Hello$Inner", "InnerMost", 0);
    194     byte[] bytes = cw.toByteArray();
    195 
    196     ClassFile classFile = com.google.turbine.bytecode.ClassReader.read(null, bytes);
    197 
    198     assertThat(classFile.innerClasses()).hasSize(2);
    199 
    200     ClassFile.InnerClass a = classFile.innerClasses().get(0);
    201     assertThat(a.access()).isEqualTo(TurbineFlag.ACC_STATIC | TurbineFlag.ACC_PRIVATE);
    202     assertThat(a.innerName()).isEqualTo("Inner");
    203     assertThat(a.innerClass()).isEqualTo("test/Hello$Inner");
    204     assertThat(a.outerClass()).isEqualTo("test/Hello");
    205 
    206     ClassFile.InnerClass b = classFile.innerClasses().get(1);
    207     assertThat(b.innerName()).isEqualTo("InnerMost");
    208     assertThat(b.innerClass()).isEqualTo("test/Hello$Inner$InnerMost");
    209     assertThat(b.outerClass()).isEqualTo("test/Hello$Inner");
    210   }
    211 
    212   @Test
    213   public void largeConstant() {
    214     String jumbo = Strings.repeat("a", Short.MAX_VALUE + 1);
    215 
    216     ClassWriter cw = new ClassWriter(0);
    217     cw.visit(52, Opcodes.ACC_SUPER, jumbo, null, "java/lang/Object", null);
    218     byte[] bytes = cw.toByteArray();
    219 
    220     ClassFile cf = ClassReader.read(null, bytes);
    221     assertThat(cf.name()).isEqualTo(jumbo);
    222   }
    223 
    224   @Test
    225   public void v53() {
    226     ClassWriter cw = new ClassWriter(0);
    227     cw.visitAnnotation("Ljava/lang/Deprecated;", true);
    228     cw.visit(
    229         53,
    230         Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_SUPER,
    231         "Hello",
    232         null,
    233         "java/lang/Object",
    234         null);
    235     ClassFile cf = ClassReader.read(null, cw.toByteArray());
    236     assertThat(cf.name()).isEqualTo("Hello");
    237   }
    238 }
    239