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    *      https://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.commons.xml.secure;
19  
20  import static org.junit.jupiter.api.Assertions.assertEquals;
21  import static org.junit.jupiter.api.Assertions.assertInstanceOf;
22  import static org.junit.jupiter.api.Assertions.assertNotNull;
23  import static org.junit.jupiter.api.Assertions.assertNull;
24  import static org.junit.jupiter.api.Assertions.assertSame;
25  import static org.junit.jupiter.api.Assertions.assertThrows;
26  
27  import java.lang.invoke.MethodHandle;
28  
29  import javax.xml.parsers.FactoryConfigurationError;
30  import javax.xml.stream.XMLInputFactory;
31  
32  import org.junit.jupiter.api.Test;
33  
34  /**
35   * Tests for {@link MethodHandleFactory}, the reflective lookup helper behind {@link SecureXMLInputFactory#newDefaultFactory()}.
36   * <p>
37   * The helper is exercised directly, including the miss and rethrow paths that no standard JVM factory lookup reaches, so the platform-specific fallback logic
38   * of the secure factory has full branch coverage.
39   * </p>
40   */
41  class MethodHandleFactoryTest {
42  
43      @Test
44      void findStaticReturnsHandleForExistingMethod() {
45          final MethodHandle handle = MethodHandleFactory.findStatic(XMLInputFactory.class, "newInstance");
46          assertNotNull(handle, "an existing static method must resolve to a handle");
47      }
48  
49      @Test
50      void findStaticReturnsNullForMissingMethod() {
51          assertNull(MethodHandleFactory.findStatic(XMLInputFactory.class, "noSuchMethod"),
52                  "a missing method must resolve to null");
53      }
54  
55      @Test
56      void invokeExactRethrowsDeclaredException() {
57          final FactoryConfigurationError declared = new FactoryConfigurationError("boom");
58          final FactoryConfigurationError thrown = assertThrows(FactoryConfigurationError.class, () -> MethodHandleFactory.invokeExact(() -> {
59              throw declared;
60          }, FactoryConfigurationError.class), "an exception of the declared type must be rethrown");
61          assertSame(declared, thrown, "the declared exception must propagate unchanged");
62      }
63  
64      @Test
65      void invokeExactRethrowsUndeclaredError() {
66          final OutOfMemoryError error = new OutOfMemoryError("boom");
67          final OutOfMemoryError thrown = assertThrows(OutOfMemoryError.class, () -> MethodHandleFactory.invokeExact(() -> {
68              throw error;
69          }, FactoryConfigurationError.class), "a JVM error must keep its type");
70          assertSame(error, thrown, "the error must propagate unchanged");
71      }
72  
73      @Test
74      void invokeExactReturnsValue() {
75          assertEquals("value", MethodHandleFactory.invokeExact(() -> "value", IllegalStateException.class), "the callable's value must be returned");
76      }
77  
78      @Test
79      void invokeExactWrapsUnexpectedException() {
80          final IllegalStateException wrapped = assertThrows(IllegalStateException.class, () -> MethodHandleFactory.invokeExact(() -> {
81              throw new IllegalArgumentException("boom");
82          }, FactoryConfigurationError.class), "an undeclared exception must be wrapped");
83          assertInstanceOf(IllegalArgumentException.class, wrapped.getCause(), "the unexpected exception must be the wrapper's cause");
84      }
85  }