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