You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ah...@apache.org on 2022/11/30 13:35:17 UTC

[commons-statistics] 01/15: Add test to assert internal method getMedian is not public/protected

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 <ah...@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