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