This is an automated email from the ASF dual-hosted git repository. aherbert pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-statistics.git
commit 6266e0f67e0391fbe9be6444958e9d192d26a312 Author: aherbert <aherb...@apache.org> AuthorDate: Wed Nov 30 11:11:53 2022 +0000 Add test to assert internal method getMedian is not public/protected --- .../BaseContinuousDistributionTest.java | 4 +++ .../distribution/BaseDiscreteDistributionTest.java | 4 +++ .../distribution/BaseDistributionTest.java | 34 ++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BaseContinuousDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BaseContinuousDistributionTest.java index 5d27d5e..1a40b0f 100644 --- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BaseContinuousDistributionTest.java +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BaseContinuousDistributionTest.java @@ -16,6 +16,7 @@ */ package org.apache.commons.statistics.distribution; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -960,6 +961,8 @@ abstract class BaseContinuousDistributionTest * The median is used internally for computation of the probability of a range * using either the CDF or survival function. If overridden by a distribution it should * be equivalent to the inverse CDF called with 0.5. + * + * <p>The method modifiers are asserted to check the method is not public or protected. */ @ParameterizedTest @MethodSource @@ -967,6 +970,7 @@ abstract class BaseContinuousDistributionTest if (dist instanceof AbstractContinuousDistribution) { final AbstractContinuousDistribution d = (AbstractContinuousDistribution) dist; TestUtils.assertEquals(d.inverseCumulativeProbability(0.5), d.getMedian(), tolerance, "median"); + assertMethodNotModified(dist.getClass(), Modifier.PUBLIC | Modifier.PROTECTED, "getMedian"); } } } diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BaseDiscreteDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BaseDiscreteDistributionTest.java index 7dad929..a36b9ef 100644 --- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BaseDiscreteDistributionTest.java +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BaseDiscreteDistributionTest.java @@ -16,6 +16,7 @@ */ package org.apache.commons.statistics.distribution; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -1154,6 +1155,8 @@ abstract class BaseDiscreteDistributionTest * The median is used internally for computation of the probability of a range * using either the CDF or survival function. If overridden by a distribution it should * be equivalent to the inverse CDF called with 0.5. + * + * <p>The method modifiers are asserted to check the method is not public or protected. */ @ParameterizedTest @MethodSource @@ -1161,6 +1164,7 @@ abstract class BaseDiscreteDistributionTest if (dist instanceof AbstractDiscreteDistribution) { final AbstractDiscreteDistribution d = (AbstractDiscreteDistribution) dist; Assertions.assertEquals(d.inverseCumulativeProbability(0.5), d.getMedian(), "median"); + assertMethodNotModified(dist.getClass(), Modifier.PUBLIC | Modifier.PROTECTED, "getMedian"); } } } diff --git a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BaseDistributionTest.java b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BaseDistributionTest.java index 2371014..9e25620 100644 --- a/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BaseDistributionTest.java +++ b/commons-statistics-distribution/src/test/java/org/apache/commons/statistics/distribution/BaseDistributionTest.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -611,6 +612,39 @@ abstract class BaseDistributionTest<T, D extends DistributionTestData> { return data.stream().map(d -> Arguments.of(d.getParameters())); } + /** + * Assert the named method on the class is not modified with the specified modifiers. + * + * <p>This uses reflection to traverse the object hierarchy to search for the named + * method. It can be used to assert that internal methods are not exposed in the API + * as public or protected. + * + * @param cls Class. + * @param modifiers Disallowed modifiers. + * @param name Name of the method. + * @param parameterTypes Array of parameter types for the method. + * @see Method#getModifiers() + * @see Class#getDeclaredMethod(String, Class...) + * @see java.lang.reflect.Modifier + */ + static void assertMethodNotModified(Class<?> cls, int modifiers, String name, Class<?>... parameterTypes) { + // getMethod will only find public methods. + // using getDeclaredMethod can access private methods but it + // only applies to the current class so we traverse the hierarchy. + for (Class<?> c = cls; c != null; c = c.getSuperclass()) { + try { + final Method method = cls.getDeclaredMethod(name, parameterTypes); + final int flags = method.getModifiers() & modifiers; + Assertions.assertEquals(0, flags, + () -> "Method " + name + " has disallowed modifiers: " + Modifier.toString(flags)); + } catch (NoSuchMethodException ignore) { + // The class does not declare the method + } catch (SecurityException e) { + Assertions.fail("Cannot search for " + name + " using reflection", e); + } + } + } + //------------------------ Tests ----------------------------- // Tests are final. It is expected that the test can be modified by overriding