diff --git a/common/junit-platform-native/src/main/java/org/graalvm/junit/platform/JUnitPlatformFeature.java b/common/junit-platform-native/src/main/java/org/graalvm/junit/platform/JUnitPlatformFeature.java index e9fc8c155..7f86b0a1a 100644 --- a/common/junit-platform-native/src/main/java/org/graalvm/junit/platform/JUnitPlatformFeature.java +++ b/common/junit-platform-native/src/main/java/org/graalvm/junit/platform/JUnitPlatformFeature.java @@ -45,6 +45,7 @@ import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.nativeimage.hosted.RuntimeClassInitialization; +import org.graalvm.nativeimage.hosted.RuntimeReflection; import org.junit.platform.engine.DiscoverySelector; import org.junit.platform.engine.discovery.DiscoverySelectors; import org.junit.platform.engine.discovery.UniqueIdSelector; @@ -66,6 +67,7 @@ import java.util.List; import java.util.Optional; import java.util.ServiceLoader; +import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -93,6 +95,27 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { Launcher launcher = LauncherFactory.create(); TestPlan testplan = discoverTestsAndRegisterTestClassesForReflection(launcher, selectors); ImageSingletons.add(NativeImageJUnitLauncher.class, new NativeImageJUnitLauncher(launcher, testplan)); + + ClassLoader applicationLoader = access.getApplicationClassLoader(); + Class typeSafeMatcher = findClassOrNull(applicationLoader, "org.hamcrest.TypeSafeMatcher"); + Class typeSafeDiagnosingMatcher = findClassOrNull(applicationLoader, "org.hamcrest.TypeSafeDiagnosingMatcher"); + if (typeSafeMatcher != null || typeSafeDiagnosingMatcher != null) { + BiConsumer> registerMatcherForReflection = (a, c) -> RuntimeReflection.registerAllDeclaredMethods(c); + if (typeSafeMatcher != null) { + access.registerSubtypeReachabilityHandler(registerMatcherForReflection, typeSafeMatcher); + } + if (typeSafeDiagnosingMatcher != null) { + access.registerSubtypeReachabilityHandler(registerMatcherForReflection, typeSafeDiagnosingMatcher); + } + } + } + + private static Class findClassOrNull(ClassLoader loader, String className) { + try { + return loader.loadClass(className); + } catch (ClassNotFoundException e) { + return null; + } } private List getSelectors(List classpathRoots) { diff --git a/common/junit-platform-native/src/test/java/org/graalvm/junit/vintage/HamcrestTest.java b/common/junit-platform-native/src/test/java/org/graalvm/junit/vintage/HamcrestTest.java new file mode 100644 index 000000000..a39296add --- /dev/null +++ b/common/junit-platform-native/src/test/java/org/graalvm/junit/vintage/HamcrestTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.graalvm.junit.vintage; + +import java.util.Arrays; +import java.util.List; + +import org.hamcrest.core.Every; +import org.hamcrest.MatcherAssert; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; + +public class HamcrestTest { + + @Test + public void testEvery() { + List numbers = Arrays.asList(1, 1, 1, 1); + MatcherAssert.assertThat(numbers, Every.everyItem(is(1))); + } + + @SuppressWarnings("deprecation") + @Rule public ExpectedException expectedException = ExpectedException.none(); + + @Test + public void testExpectedException() { + expectedException.expect(ArithmeticException.class); + throw new ArithmeticException(); + } + + @Test + public void testExpectedExceptionCause() { + expectedException.expectCause(instanceOf(ArithmeticException.class)); + try { + throw new ArithmeticException(); + } catch (ArithmeticException e) { + throw new RuntimeException(e); + } + } +}