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.verifier;
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  import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
26  import static org.junit.jupiter.api.Assertions.assertTrue;
27  
28  import java.io.File;
29  import java.io.IOException;
30  import java.net.URISyntaxException;
31  import java.util.Enumeration;
32  import java.util.jar.JarEntry;
33  import java.util.jar.JarFile;
34  
35  import org.apache.bcel.classfile.JavaClass;
36  import org.apache.bcel.classfile.NestHost;
37  import org.apache.bcel.classfile.Utility;
38  import org.apache.bcel.verifier.exc.AssertionViolatedException;
39  import org.apache.bcel.verifier.input.FieldVerifierChildClass;
40  import org.apache.bcel.verifier.input.StaticFieldVerifierChildClass;
41  import org.apache.bcel.verifier.statics.StringRepresentation;
42  import org.apache.commons.lang3.Strings;
43  import org.apache.commons.lang3.SystemProperties;
44  import org.junit.jupiter.api.AfterEach;
45  import org.junit.jupiter.api.Test;
46  import org.junit.jupiter.api.condition.DisabledForJreRange;
47  import org.junit.jupiter.api.condition.JRE;
48  
49  class VerifierTest {
50  
51      private static File getJarFile(final Class<?> clazz) throws URISyntaxException {
52          return new File(clazz.getProtectionDomain().getCodeSource().getLocation().toURI());
53      }
54  
55      private static void testDefaultMethodValidation(final String className, final String... excludes) throws ClassNotFoundException {
56          if (Strings.CS.endsWithAny(className, excludes)) {
57              return;
58          }
59          final Verifier verifier = VerifierFactory.getVerifier(className);
60          VerificationResult result = verifier.doPass1();
61  
62          assertEquals(VerificationResult.VERIFIED_OK, result.getStatus(), "Pass 1 verification of " + className + " failed: " + result.getMessage());
63  
64          result = verifier.doPass2();
65  
66          assertEquals(VerificationResult.VERIFIED_OK, result.getStatus(), "Pass 2 verification of " + className + " failed: " + result.getMessage());
67  
68          if (result == VerificationResult.VR_OK) {
69              final JavaClass jc = org.apache.bcel.Repository.lookupClass(className);
70              for (int i = 0; i < jc.getMethods().length; i++) {
71                  result = verifier.doPass3a(i);
72                  assertEquals(VerificationResult.VR_OK, result, "Pass 3a, method number " + i + " ['" + jc.getMethods()[i] + "']:\n" + result);
73                  result = verifier.doPass3b(i);
74                  assertEquals(VerificationResult.VR_OK, result, "Pass 3b, method number " + i + " ['" + jc.getMethods()[i] + "']:\n" + result);
75              }
76          }
77      }
78  
79      private static void testJarFile(final File file, final String... excludes) throws IOException, ClassNotFoundException {
80          try (JarFile jarFile = new JarFile(file)) {
81              final Enumeration<JarEntry> entries = jarFile.entries();
82              while (entries.hasMoreElements()) {
83                  final JarEntry jarEntry = entries.nextElement();
84                  String entryName = jarEntry.getName();
85                  if (entryName.endsWith(JavaClass.EXTENSION)) {
86                      entryName = entryName.replaceFirst("\\.class$", "");
87                      entryName = Utility.compactClassName(entryName, false);
88                      testDefaultMethodValidation(entryName, excludes);
89                  }
90              }
91          }
92      }
93  
94      private static void testNestHostWithJavaVersion(final String className) throws ClassNotFoundException {
95          final String version = SystemProperties.getJavaVersion();
96          assertNotNull(version);
97          try {
98              testDefaultMethodValidation(className);
99              assertTrue(version.startsWith("1."));
100         } catch (final AssertionViolatedException e) {
101             assertFalse(version.startsWith("1."));
102             final StringBuilder expectedMessage = new StringBuilder();
103             expectedMessage.append("INTERNAL ERROR: Please adapt '");
104             expectedMessage.append(StringRepresentation.class);
105             expectedMessage.append("' to deal with objects of class '");
106             expectedMessage.append(NestHost.class);
107             expectedMessage.append("'.");
108             assertEquals(expectedMessage.toString(), e.getCause().getMessage());
109         }
110     }
111 
112     @AfterEach
113     public void afterEach() {
114         VerifierFactory.clear();
115     }
116 
117     @Test
118     void testArrayUtils() throws ClassNotFoundException {
119         testNestHostWithJavaVersion("org.apache.commons.lang.ArrayUtils");
120     }
121 
122     @Test
123     void testCollection() throws ClassNotFoundException {
124         testDefaultMethodValidation("java.util.Collection");
125     }
126 
127     @Test
128     void testCommonsLang2() throws IOException, URISyntaxException, ClassNotFoundException {
129         testJarFile(getJarFile(org.apache.commons.lang.StringUtils.class), "ArrayUtils", "SerializationUtils");
130     }
131 
132     @Test
133     void testDefinitionImpl() throws ClassNotFoundException {
134         testNestHostWithJavaVersion("com.ibm.wsdl.DefinitionImpl");
135     }
136 
137     @Test
138     void testJvmOpCodes() throws ClassNotFoundException {
139         testDefaultMethodValidation("org.apache.bcel.verifier.tests.JvmOpCodes");
140     }
141 
142     @Test
143     @DisabledForJreRange(max = JRE.JAVA_8)
144     void testObjectInputStream() throws ClassNotFoundException {
145         testNestHostWithJavaVersion("java.io.ObjectInputStream");
146     }
147 
148     @Test
149     @DisabledForJreRange(min = JRE.JAVA_9)
150     void testObjectInputStreamJDK8() {
151         assertThrowsExactly(UnsupportedOperationException.class, () -> testNestHostWithJavaVersion("java.io.ObjectInputStream"));
152     }
153 
154     @Test
155     void testPackagePrivateField() throws ClassNotFoundException {
156         testDefaultMethodValidation(FieldVerifierChildClass.class.getName());
157     }
158 
159     @Test
160     void testPackagePrivateStaticField() throws ClassNotFoundException {
161         testDefaultMethodValidation(StaticFieldVerifierChildClass.class.getName());
162     }
163 
164     @Test
165     void testWSDL() throws IOException, URISyntaxException, ClassNotFoundException {
166         testJarFile(getJarFile(javax.wsdl.Port.class), "WSDLReaderImpl", "DefinitionImpl");
167     }
168 }