diff --git a/build.gradle b/build.gradle index a5c9fb25e0..c755b3bd4f 100644 --- a/build.gradle +++ b/build.gradle @@ -96,6 +96,8 @@ dependencies { implementation libraries.objenesis testImplementation libraries.assertj + testImplementation libraries.junitJupiterApi + testImplementation libraries.junitJupiterParams testUtil sourceSets.test.output diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index 53e1dcdc5b..30354d1f42 100644 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -10,6 +10,7 @@ versions.errorprone = '2.23.0' libraries.junit4 = 'junit:junit:4.13.2' libraries.junitJupiterApi = "org.junit.jupiter:junit-jupiter-api:${versions.junitJupiter}" +libraries.junitJupiterParams = "org.junit.jupiter:junit-jupiter-params:${versions.junitJupiter}" libraries.junitPlatformLauncher = 'org.junit.platform:junit-platform-launcher:1.10.0' libraries.junitJupiterEngine = "org.junit.jupiter:junit-jupiter-engine:${versions.junitJupiter}" libraries.junitVintageEngine = "org.junit.vintage:junit-vintage-engine:${versions.junitJupiter}" diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/InlineDelegateByteBuddyMockMaker.java b/src/main/java/org/mockito/internal/creation/bytebuddy/InlineDelegateByteBuddyMockMaker.java index d40967f94e..02f39a35a5 100644 --- a/src/main/java/org/mockito/internal/creation/bytebuddy/InlineDelegateByteBuddyMockMaker.java +++ b/src/main/java/org/mockito/internal/creation/bytebuddy/InlineDelegateByteBuddyMockMaker.java @@ -207,9 +207,7 @@ class InlineDelegateByteBuddyMockMaker InlineDelegateByteBuddyMockMaker() { if (INITIALIZATION_ERROR != null) { String detail; - if (System.getProperty("java.specification.vendor", "") - .toLowerCase() - .contains("android")) { + if (PlatformUtils.isAndroidPlatform() || PlatformUtils.isProbablyTermuxEnvironment()) { detail = "It appears as if you are trying to run this mock maker on Android which does not support the instrumentation API."; } else { diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/PlatformUtils.java b/src/main/java/org/mockito/internal/creation/bytebuddy/PlatformUtils.java new file mode 100644 index 0000000000..0fa235d3d7 --- /dev/null +++ b/src/main/java/org/mockito/internal/creation/bytebuddy/PlatformUtils.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 Mockito contributors + * This program is made available under the terms of the MIT License. + */ +package org.mockito.internal.creation.bytebuddy; + +/** + * Helpers for various platform detection mechanisms related to the ByteBuddy mock maker. + * + * @author Ashley Scopes + */ +final class PlatformUtils { + private PlatformUtils() { + // Static-only class. + } + + static boolean isAndroidPlatform() { + return System.getProperty("java.specification.vendor", "") + .toLowerCase() + .contains("android"); + } + + static boolean isProbablyTermuxEnvironment() { + boolean isLinux = System.getProperty("os.name", "").equalsIgnoreCase("linux"); + boolean isInTermuxData = + System.getProperty("java.home", "").toLowerCase().contains("/com.termux/"); + return isLinux && isInTermuxData; + } +} diff --git a/src/test/java/org/mockito/internal/creation/bytebuddy/PlatformUtilsTest.java b/src/test/java/org/mockito/internal/creation/bytebuddy/PlatformUtilsTest.java new file mode 100644 index 0000000000..ba2263715d --- /dev/null +++ b/src/test/java/org/mockito/internal/creation/bytebuddy/PlatformUtilsTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2023 Mockito contributors + * This program is made available under the terms of the MIT License. + */ +package org.mockito.internal.creation.bytebuddy; + +import java.util.Properties; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.parallel.Isolated; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Ashley Scopes + */ +@Isolated("modifies system properties temporarily") +class PlatformUtilsTest { + Properties globalProperties; + + @BeforeEach + void setUp() { + globalProperties = new Properties(); + globalProperties.putAll(System.getProperties()); + System.getProperties().clear(); + } + + @AfterEach + void tearDown() { + System.getProperties().clear(); + System.getProperties().putAll(globalProperties); + } + + @CsvSource( + value = { + "java.specification.vendor, expected result", + " android, true", + " AnDrOId, true", + " anythingElse, false", + " , false", + }, + useHeadersInDisplayName = true) + @ParameterizedTest + void isAndroidPlatform_returns_expected_value(String vendor, boolean result) { + // Given + setProperty("java.specification.vendor", vendor); + + // Then + assertThat(PlatformUtils.isAndroidPlatform()).isEqualTo(result); + } + + @CsvSource( + value = { + " os.name, java.home, expected result", + " linux, /data/data/com.termux/whatever, true", + " linux, /foo/bar/com.termux/somedir, true", + " LINUX, /data/data/com.termux/whatever, true", + " Linux, /foo/bar/com.termux/somedir, true", + "Mac OS X 13.0, /foo/bar/com.termux/somedir, false", + " Windows 10, /foo/bar/com.termux/somedir, false", + " OS/2, /foo/bar/com.termux/somedir, false", + " Linux, /usr/share/java, false", + " , , false", + " foo, , false", + " , foo, false", + " linux, , false", + " , /data/data/com.termux/whatever, false", + }, + useHeadersInDisplayName = true) + @ParameterizedTest + void isProbablyTermuxEnvironment_returns_expected_value( + String os, String javaHome, boolean result) { + // Given + setProperty("os.name", os); + setProperty("java.home", javaHome); + + // Then + assertThat(PlatformUtils.isProbablyTermuxEnvironment()).isEqualTo(result); + } + + static void setProperty(String name, String value) { + if (value == null) { + System.clearProperty(name); + } else { + System.setProperty(name, value); + } + } +}