View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.bcel;
19  
20  import static org.junit.jupiter.api.Assertions.assertEquals;
21  import static org.junit.jupiter.api.Assertions.assertFalse;
22  import static org.junit.jupiter.api.Assertions.assertNotNull;
23  
24  import java.util.stream.Stream;
25  
26  import org.apache.bcel.classfile.Code;
27  import org.apache.bcel.classfile.JavaClass;
28  import org.apache.bcel.classfile.LineNumber;
29  import org.apache.bcel.classfile.LineNumberTable;
30  import org.apache.bcel.classfile.LocalVariable;
31  import org.apache.bcel.classfile.LocalVariableTable;
32  import org.apache.bcel.classfile.Method;
33  import org.apache.bcel.classfile.Utility;
34  import org.apache.bcel.generic.ClassGen;
35  import org.apache.bcel.generic.ConstantPoolGen;
36  import org.apache.bcel.generic.InstructionHandle;
37  import org.apache.bcel.generic.InstructionList;
38  import org.apache.bcel.generic.InvokeInstruction;
39  import org.apache.bcel.generic.MethodGen;
40  import org.apache.bcel.generic.Type;
41  import org.junit.jupiter.api.Test;
42  import org.junit.jupiter.params.ParameterizedTest;
43  import org.junit.jupiter.params.provider.ValueSource;
44  
45  public class PLSETestCase extends AbstractTestCase {
46      /**
47       * BCEL-208: A couple of methods in MethodGen.java need to test for an empty instruction list.
48       */
49      @Test
50      public void testBCEL208() throws ClassNotFoundException {
51          final JavaClass clazz = getTestJavaClass(PACKAGE_BASE_NAME + ".data.PLSETestClass");
52          final ClassGen gen = new ClassGen(clazz);
53          final ConstantPoolGen pool = gen.getConstantPool();
54          final Method m = gen.getMethodAt(1);
55          final MethodGen mg = new MethodGen(m, gen.getClassName(), pool);
56          mg.setInstructionList(null);
57          mg.addLocalVariable("local2", Type.INT, null, null);
58          // currently, this will cause null pointer exception
59          mg.getLocalVariableTable(pool);
60      }
61  
62      /**
63       * BCEL-262:
64       */
65      @Test
66      public void testBCEL262() throws ClassNotFoundException {
67          final JavaClass clazz = getTestJavaClass(PACKAGE_BASE_NAME + ".data.PLSETestEnum");
68          final ClassGen gen = new ClassGen(clazz);
69          final ConstantPoolGen pool = gen.getConstantPool();
70          // get the values() method
71          final Method m = gen.getMethodAt(0);
72          final MethodGen mg = new MethodGen(m, gen.getClassName(), pool);
73          final InstructionList il = mg.getInstructionList();
74          // get the invokevirtual instruction
75          final InstructionHandle ih = il.findHandle(3);
76          final InvokeInstruction ii = (InvokeInstruction) ih.getInstruction();
77          // without fix, the getClassName() will throw:
78          // java.lang.IllegalArgumentException: Cannot be used on an array type
79          final String cn = ii.getClassName(pool);
80          assertEquals("[Lorg.apache.bcel.data.PLSETestEnum;", cn);
81      }
82  
83      /**
84       * BCEL-295:
85       */
86      @Test
87      public void testBCEL295() throws Exception {
88          final JavaClass clazz = getTestJavaClass(PACKAGE_BASE_NAME + ".data.PLSETestClass2");
89          final ClassGen cg = new ClassGen(clazz);
90          final ConstantPoolGen pool = cg.getConstantPool();
91          final Method m = cg.getMethodAt(1); // 'main'
92          final LocalVariableTable lvt = m.getLocalVariableTable();
93          final LocalVariable lv = lvt.getLocalVariable(2, 4); // 'i'
94          // System.out.println(lv);
95          final MethodGen mg = new MethodGen(m, cg.getClassName(), pool);
96          final LocalVariableTable newLvt = mg.getLocalVariableTable(mg.getConstantPool());
97          final LocalVariable newLv = newLvt.getLocalVariable(2, 4); // 'i'
98          // System.out.println(new_lv);
99          assertEquals(lv.getLength(), newLv.getLength(), "live range length");
100     }
101 
102     /**
103      * BCEL-361: LineNumber.toString() treats code offset as signed
104      */
105     @Test
106     public void testBCEL361() throws Exception {
107         final JavaClass clazz = getTestJavaClass(PACKAGE_BASE_NAME + ".data.LargeMethod");
108         final Method[] methods = clazz.getMethods();
109         final Method m = methods[0];
110         // System.out.println(m.getName());
111         final Code code = m.getCode();
112         final LineNumberTable lnt = code.getLineNumberTable();
113         final LineNumber[] lineNumbers = lnt.getLineNumberTable();
114         final String data = lineNumbers[lineNumbers.length - 1].toString();
115         // System.out.println(data);
116         // System.out.println(data.contains("-"));
117         assertFalse(data.contains("-"), "code offsets must be positive");
118         Stream.of(lineNumbers).forEach(ln -> assertFalse(ln.getLineNumber() < 0));
119         Stream.of(lineNumbers).forEach(ln -> assertFalse(ln.getStartPC() < 0));
120     }
121 
122     /**
123      * BCEL-79:
124      */
125     @Test
126     public void testBCEL79() throws ClassNotFoundException {
127         final JavaClass clazz = getTestJavaClass(PACKAGE_BASE_NAME + ".data.PLSETestClass");
128         final ClassGen gen = new ClassGen(clazz);
129         final ConstantPoolGen pool = gen.getConstantPool();
130         final Method m = gen.getMethodAt(2);
131         final LocalVariableTable lvt = m.getLocalVariableTable();
132         // System.out.println(lvt);
133         // System.out.println(lvt.getTableLength());
134         final MethodGen mg = new MethodGen(m, gen.getClassName(), pool);
135         final LocalVariableTable newLvt = mg.getLocalVariableTable(mg.getConstantPool());
136         // System.out.println(new_lvt);
137         assertEquals(lvt.getTableLength(), newLvt.getTableLength(), "number of locals");
138     }
139 
140     /**
141      * Test to improve BCEL tests code coverage for classfile/Utility.java.
142      */
143     @ParameterizedTest
144     @ValueSource(booleans = { true, false })
145     public void testCoverage(final boolean compress) throws ClassNotFoundException, java.io.IOException {
146         // load a class with a wide variety of byte codes - including tableswitch and lookupswitch
147         final JavaClass clazz = getTestJavaClass(PACKAGE_BASE_NAME + ".data.ConstantPoolX");
148         for (final Method m : clazz.getMethods()) {
149             final String signature = m.getSignature();
150             Utility.methodTypeToSignature(Utility.methodSignatureReturnType(signature), Utility.methodSignatureArgumentTypes(signature)); // discard result
151             final Code code = m.getCode();
152             if (code != null) {
153                 // TODO: need for real assertions here
154                 final String encoded = Utility.encode(code.getCode(), compress);
155                 assertNotNull(encoded);
156                 // following statement will throw exeception without classfile/Utility.encode fix
157                 assertNotNull(Utility.decode(encoded, compress));
158                 assertNotNull(code.toString());
159             }
160         }
161     }
162 }